Changes in / [17f6079:c8b8c83]


Ignore:
Files:
21 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    r17f6079 rc8b8c83  
    156156$(OTR_PI): %.so: $(SRCDIR)%.c
    157157        @echo '*' Building plugin $@
    158         @$(CC) $(CFLAGS) $(OTRFLAGS) -fPIC -shared $< -o $@
     158        @$(CC) $(CFLAGS) $(OTRFLAGS) -fPIC -shared $(LDFLAGS) $< -o $@
    159159
    160160$(SKYPE_PI): $(SRCDIR)protocols/skype/skype.c
  • bitlbee.h

    r17f6079 rc8b8c83  
    3535
    3636#define PACKAGE "BitlBee"
    37 #define BITLBEE_VERSION "3.0.2"
     37#define BITLBEE_VERSION "3.0.3"
    3838#define VERSION BITLBEE_VERSION
    3939#define BITLBEE_VER(a,b,c) (((a) << 16) + ((b) << 8) + (c))
    40 #define BITLBEE_VERSION_CODE BITLBEE_VER(3, 0, 2)
     40#define BITLBEE_VERSION_CODE BITLBEE_VER(3, 0, 3)
    4141
    4242#define MAX_STRING 511
  • debian/changelog

    r17f6079 rc8b8c83  
     1bitlbee (3.0.3-1) unstable; urgency=low
     2
     3  * New upstream release. (Skipped 3.0.2, sorry!)
     4  * Fixes Twitter issues.
     5
     6 -- Wilmer van der Gaast <wilmer@gaast.net>  Tue, 14 Jun 2011 22:39:22 +0100
     7
    18bitlbee (3.0.1-1) unstable; urgency=low
    29
  • debian/rules

    r17f6079 rc8b8c83  
    9595        dh_shlibdeps
    9696ifdef BITLBEE_VERSION
    97         dh_gencontrol -- -v1:$(BITLBEE_VERSION)-0  -Vbee:Version=1:$(BITLBEE_VERSION)-0
     97        dh_gencontrol -- -v$(BITLBEE_VERSION)  -Vbee:Version=$(BITLBEE_VERSION)
    9898else
    9999        dh_gencontrol -- -Vbee:Version=$(shell dpkg-parsechangelog | grep ^Version: | awk '{print $$2}' | sed -e 's/+b[0-9]\+$$//')
  • doc/CHANGES

    r17f6079 rc8b8c83  
    33
    44http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on
     5
     6Version 3.0.3:
     7- Fixed Twitter compatibility. (The API call used to get the following list
     8  was deprecated.)
     9- Twitter: Enable the show_ids setting to assign a two-digit short ID to
     10  recent tweets to use for retweets and replies (so you can RT/reply to more
     11  than just a person's last message).
     12- Some other Twitter fixes/improvements.
     13- "otr reconnect" command and some other fixes.
     14- GnuTLS 2.12 compatibility fix.
     15- Include "FLOOD=0/9999" in the 005/ISUPPORT line at login to hint the IRC
     16  client that rate limiting is not required. (Next step: Get IRC clients to
     17  parse it.)
     18- Other stuff too small to mention.
     19
     20Finished 12 Jun 2011
    521
    622Version 3.0.2:
  • doc/bitlbee.xinetd

    r17f6079 rc8b8c83  
    1212        ## You most likely want to change these two
    1313        user            = nobody
    14         server          = /usr/local/sbin/bitlbee
     14        server          = /usr/local/sbin/bitlbee -I
    1515       
    1616        ## You might want to limit access to localhost only:
  • doc/user-guide/commands.xml

    r17f6079 rc8b8c83  
    393393
    394394                        <para>
    395                                 Available subcommands: connect, disconnect, smp, smpq, trust, info, keygen, and forget. See <emphasis>help otr &lt;subcommand&gt;</emphasis> for more information.
     395                                Available subcommands: connect, disconnect, reconnect, smp, smpq, trust, info, keygen, and forget. See <emphasis>help otr &lt;subcommand&gt;</emphasis> for more information.
    396396                        </para>
    397397
     
    418418                                <para>
    419419                                        Resets the connection with the specified user to cleartext.
     420                                </para>
     421                               
     422                        </description>
     423               
     424                </bitlbee-command>
     425               
     426                <bitlbee-command name="reconnect">
     427                        <syntax>otr reconnect &lt;nick&gt;</syntax>
     428                       
     429                        <description>
     430                       
     431                                <para>
     432                                        Breaks and re-establishes the encrypted connection with the specified user. Useful if something got desynced.
     433                                </para>
     434                               
     435                                <para>
     436                                        Equivalent to <emphasis>otr disconnect</emphasis> followed by <emphasis>otr connect</emphasis>.
    420437                                </para>
    421438                               
     
    754771
    755772        <bitlbee-setting name="base_url" type="string" scope="account">
    756                 <default>http://twitter.com</default>
     773                <default>http://api.twitter.com/1</default>
    757774
    758775                <description>
     
    837854                                <varlistentry><term>undo [&lt;id&gt;]</term><listitem><para>Delete your last Tweet (or one with the given ID)</para></listitem></varlistentry>
    838855                                <varlistentry><term>rt &lt;screenname|id&gt;</term><listitem><para>Retweet someone's last Tweet (or one with the given ID)</para></listitem></varlistentry>
     856                                <varlistentry><term>reply &lt;screenname|id&gt;</term><listitem><para>Reply to a Tweet (with a reply-to reference)</para></listitem></varlistentry>
    839857                                <varlistentry><term>follow &lt;screenname&gt;</term><listitem><para>Start following a person</para></listitem></varlistentry>
    840858                                <varlistentry><term>unfollow &lt;screenname&gt;</term><listitem><para>Stop following a person</para></listitem></varlistentry>
     
    13091327                        <para>
    13101328                                Can be set for Jabber- and OSCAR-connections. For Jabber, you might have to set this if the servername isn't equal to the part after the @ in the Jabber handle. For OSCAR this shouldn't be necessary anymore in recent BitlBee versions.
     1329                        </para>
     1330                </description>
     1331        </bitlbee-setting>
     1332
     1333        <bitlbee-setting name="show_ids" type="boolean" scope="account">
     1334                <default>false</default>
     1335
     1336                <description>
     1337                        <para>
     1338                                Enable this setting on a Twitter account to have BitlBee include a two-digit "id" in front of every message. This id can then be used for replies and retweets.
    13111339                        </para>
    13121340                </description>
  • init/bitlbee@.service.in

    r17f6079 rc8b8c83  
    44
    55[Service]
    6 ExecStart=@sbindir@/bitlbee
     6ExecStart=@sbindir@/bitlbee -I
    77StandardInput=socket
    88User=bitlbee
  • irc_commands.c

    r17f6079 rc8b8c83  
    637637                   Jabber really doesn't like them. */
    638638                for( i = j = 0; cmd[1][i]; i ++ )
    639                         if( ( away[j] = cmd[1][i] ) >= ' ' )
     639                        if( (unsigned char) ( away[j] = cmd[1][i] ) >= ' ' )
    640640                                j ++;
    641641                away[j] = '\0';
  • irc_im.c

    r17f6079 rc8b8c83  
    600600       
    601601        ic->data = NULL;
     602        c->ui_data = NULL;
    602603        irc_channel_del_user( ic, ic->irc->user, IRC_CDU_KICK, "Chatroom closed by server" );
    603604       
     
    905906                c->ic->acc->prpl->chat_leave( c );
    906907       
     908        /* Remove references in both directions now. We don't need each other anymore. */
    907909        ic->data = NULL;
     910        if( c )
     911                c->ui_data = NULL;
    908912       
    909913        return TRUE;
  • lib/http_client.c

    r17f6079 rc8b8c83  
    9393        request = g_strdup_printf( "GET %s HTTP/1.0\r\n"
    9494                                   "Host: %s\r\n"
     95                                   "Connection: close\r\n"
    9596                                   "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n"
    9697                                   "\r\n", url->file, url->host );
  • lib/misc.c

    r17f6079 rc8b8c83  
    400400        cd = g_iconv_open( to_cs, from_cs );
    401401        if( cd == (GIConv) -1 )
    402                 return( -1 );
     402                return -1;
    403403       
    404404        inbytesleft = size ? size : strlen( src );
     
    408408        g_iconv_close( cd );
    409409       
    410         if( res == (size_t) -1 )
    411                 return( -1 );
     410        if( res != 0 )
     411                return -1;
    412412        else
    413                 return( outbuf - dst );
     413                return outbuf - dst;
    414414}
    415415
  • lib/oauth.c

    r17f6079 rc8b8c83  
    286286                             "Content-Type: application/x-www-form-urlencoded\r\n"
    287287                             "Content-Length: %zd\r\n"
     288                             "Connection: close\r\n"
    288289                             "\r\n"
    289290                             "%s", url_p.file, url_p.host, strlen( post ), post );
  • lib/proxy.c

    r17f6079 rc8b8c83  
    8585                                closesocket(source);
    8686                                dup2(new_fd, source);
     87                                closesocket(new_fd);
    8788                                phb->inpa = b_input_add(source, B_EV_IO_WRITE, gaim_io_connected, phb);
    8889                                return FALSE;
  • lib/ssl_gnutls.c

    r17f6079 rc8b8c83  
    135135        gnutls_certificate_allocate_credentials( &conn->xcred );
    136136        gnutls_init( &conn->session, GNUTLS_CLIENT );
     137        gnutls_transport_set_lowat( conn->session, 1 );
    137138        gnutls_set_default_priority( conn->session );
    138139        gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred );
  • otr.c

    r17f6079 rc8b8c83  
    8686void cmd_otr_connect(irc_t *irc, char **args);
    8787void cmd_otr_disconnect(irc_t *irc, char **args);
     88void cmd_otr_reconnect(irc_t *irc, char **args);
    8889void cmd_otr_smp(irc_t *irc, char **args);
    8990void cmd_otr_smpq(irc_t *irc, char **args);
     
    9697        { "connect",     1, &cmd_otr_connect,    0 },
    9798        { "disconnect",  1, &cmd_otr_disconnect, 0 },
     99        { "reconnect",   1, &cmd_otr_reconnect,  0 },
    98100        { "smp",         2, &cmd_otr_smp,        0 },
    99101        { "smpq",        3, &cmd_otr_smpq,       0 },
     
    693695
    694696/*** OTR sub-command handlers ***/
     697
     698void cmd_otr_reconnect(irc_t *irc, char **args)
     699{
     700        cmd_otr_disconnect(irc, args);
     701        cmd_otr_connect(irc, args);
     702}
    695703
    696704void cmd_otr_disconnect(irc_t *irc, char **args)
  • protocols/twitter/twitter.c

    r17f6079 rc8b8c83  
    3737                        imcb_log( ic, fmt );                        \
    3838        } while( 0 );
    39                
     39
    4040GSList *twitter_connections = NULL;
    4141
     
    4646{
    4747        struct im_connection *ic = data;
    48        
     48
    4949        // Check if we are still logged in...
    50         if (!g_slist_find( twitter_connections, ic ))
     50        if (!g_slist_find(twitter_connections, ic))
    5151                return 0;
    5252
     
    5858}
    5959
    60 static void twitter_main_loop_start( struct im_connection *ic )
     60static void twitter_main_loop_start(struct im_connection *ic)
    6161{
    6262        struct twitter_data *td = ic->proto_data;
    63        
    64         imcb_log( ic, "Getting initial statuses" );
     63
     64        imcb_log(ic, "Getting initial statuses");
    6565
    6666        // Run this once. After this queue the main loop function.
     
    7272}
    7373
    74 static void twitter_oauth_start( struct im_connection *ic );
    75 
    76 void twitter_login_finish( struct im_connection *ic )
     74static void twitter_oauth_start(struct im_connection *ic);
     75
     76void twitter_login_finish(struct im_connection *ic)
    7777{
    7878        struct twitter_data *td = ic->proto_data;
    79        
    80         if( set_getbool( &ic->acc->set, "oauth" ) && !td->oauth_info )
    81                 twitter_oauth_start( ic );
    82         else if( g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "one" ) != 0 &&
    83                  !( td->flags & TWITTER_HAVE_FRIENDS ) )
    84         {
    85                 imcb_log( ic, "Getting contact list" );
    86                 twitter_get_statuses_friends( ic, -1 );
    87         }
    88         else
    89                 twitter_main_loop_start( ic );
    90 }
    91 
    92 static const struct oauth_service twitter_oauth =
    93 {
     79
     80        if (set_getbool(&ic->acc->set, "oauth") && !td->oauth_info)
     81                twitter_oauth_start(ic);
     82        else if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "one") != 0 &&
     83                 !(td->flags & TWITTER_HAVE_FRIENDS)) {
     84                imcb_log(ic, "Getting contact list");
     85                twitter_get_friends_ids(ic, -1);
     86                //twitter_get_statuses_friends(ic, -1);
     87        } else
     88                twitter_main_loop_start(ic);
     89}
     90
     91static const struct oauth_service twitter_oauth = {
    9492        "http://api.twitter.com/oauth/request_token",
    9593        "http://api.twitter.com/oauth/access_token",
     
    9997};
    10098
    101 static const struct oauth_service identica_oauth =
    102 {
     99static const struct oauth_service identica_oauth = {
    103100        "http://identi.ca/api/oauth/request_token",
    104101        "http://identi.ca/api/oauth/access_token",
     
    108105};
    109106
    110 static gboolean twitter_oauth_callback( struct oauth_info *info );
    111 
    112 static const struct oauth_service *get_oauth_service( struct im_connection *ic )
     107static gboolean twitter_oauth_callback(struct oauth_info *info);
     108
     109static const struct oauth_service *get_oauth_service(struct im_connection *ic)
    113110{
    114111        struct twitter_data *td = ic->proto_data;
    115        
    116         if( strstr( td->url_host, "identi.ca" ) )
     112
     113        if (strstr(td->url_host, "identi.ca"))
    117114                return &identica_oauth;
    118115        else
    119116                return &twitter_oauth;
    120        
     117
    121118        /* Could add more services, or allow configuring your own base URL +
    122119           API keys. */
    123120}
    124121
    125 static void twitter_oauth_start( struct im_connection *ic )
     122static void twitter_oauth_start(struct im_connection *ic)
    126123{
    127124        struct twitter_data *td = ic->proto_data;
    128        
    129         imcb_log( ic, "Requesting OAuth request token" );
    130 
    131         td->oauth_info = oauth_request_token( get_oauth_service( ic ), twitter_oauth_callback, ic );
    132        
     125
     126        imcb_log(ic, "Requesting OAuth request token");
     127
     128        td->oauth_info = oauth_request_token(get_oauth_service(ic), twitter_oauth_callback, ic);
     129
    133130        /* We need help from the user to complete OAuth login, so don't time
    134131           out on this login. */
     
    136133}
    137134
    138 static gboolean twitter_oauth_callback( struct oauth_info *info )
     135static gboolean twitter_oauth_callback(struct oauth_info *info)
    139136{
    140137        struct im_connection *ic = info->data;
    141138        struct twitter_data *td;
    142        
    143         if( !g_slist_find( twitter_connections, ic ) )
     139
     140        if (!g_slist_find(twitter_connections, ic))
    144141                return FALSE;
    145        
     142
    146143        td = ic->proto_data;
    147         if( info->stage == OAUTH_REQUEST_TOKEN )
    148         {
    149                 char name[strlen(ic->acc->user)+9], *msg;
    150                
    151                 if( info->request_token == NULL )
    152                 {
    153                         imcb_error( ic, "OAuth error: %s", info->http->status_string );
    154                         imc_logout( ic, TRUE );
     144        if (info->stage == OAUTH_REQUEST_TOKEN) {
     145                char name[strlen(ic->acc->user) + 9], *msg;
     146
     147                if (info->request_token == NULL) {
     148                        imcb_error(ic, "OAuth error: %s", twitter_parse_error(info->http));
     149                        imc_logout(ic, TRUE);
    155150                        return FALSE;
    156151                }
    157                
    158                 sprintf( name, "%s_%s", td->prefix, ic->acc->user );
    159                 msg = g_strdup_printf( "To finish OAuth authentication, please visit "
    160                                        "%s and respond with the resulting PIN code.",
    161                                        info->auth_url );
    162                 imcb_buddy_msg( ic, name, msg, 0, 0 );
    163                 g_free( msg );
    164         }
    165         else if( info->stage == OAUTH_ACCESS_TOKEN )
    166         {
    167                 if( info->token == NULL || info->token_secret == NULL )
    168                 {
    169                         imcb_error( ic, "OAuth error: %s", info->http->status_string );
    170                         imc_logout( ic, TRUE );
     152
     153                sprintf(name, "%s_%s", td->prefix, ic->acc->user);
     154                msg = g_strdup_printf("To finish OAuth authentication, please visit "
     155                                      "%s and respond with the resulting PIN code.",
     156                                      info->auth_url);
     157                imcb_buddy_msg(ic, name, msg, 0, 0);
     158                g_free(msg);
     159        } else if (info->stage == OAUTH_ACCESS_TOKEN) {
     160                if (info->token == NULL || info->token_secret == NULL) {
     161                        imcb_error(ic, "OAuth error: %s", twitter_parse_error(info->http));
     162                        imc_logout(ic, TRUE);
    171163                        return FALSE;
     164                } else {
     165                        const char *sn = oauth_params_get(&info->params, "screen_name");
     166
     167                        if (sn != NULL && ic->acc->prpl->handle_cmp(sn, ic->acc->user) != 0) {
     168                                imcb_log(ic, "Warning: You logged in via OAuth as %s "
     169                                         "instead of %s.", sn, ic->acc->user);
     170                        }
     171                        g_free(td->user);
     172                        td->user = g_strdup(sn);
    172173                }
    173                 else
    174                 {
    175                         const char *sn = oauth_params_get( &info->params, "screen_name" );
    176                        
    177                         if( sn != NULL && ic->acc->prpl->handle_cmp( sn, ic->acc->user ) != 0 )
    178                         {
    179                                 imcb_log( ic, "Warning: You logged in via OAuth as %s "
    180                                           "instead of %s.", sn, ic->acc->user );
    181                         }
    182                 }
    183                
     174
    184175                /* IM mods didn't do this so far and it's ugly but I should
    185176                   be able to get away with it... */
    186                 g_free( ic->acc->pass );
    187                 ic->acc->pass = oauth_to_string( info );
    188                
    189                 twitter_login_finish( ic );
    190         }
    191        
     177                g_free(ic->acc->pass);
     178                ic->acc->pass = oauth_to_string(info);
     179
     180                twitter_login_finish(ic);
     181        }
     182
    192183        return TRUE;
    193184}
    194185
    195186
    196 static char *set_eval_mode( set_t *set, char *value )
    197 {
    198         if( g_strcasecmp( value, "one" ) == 0 ||
    199             g_strcasecmp( value, "many" ) == 0 ||
    200             g_strcasecmp( value, "chat" ) == 0 )
     187static char *set_eval_mode(set_t * set, char *value)
     188{
     189        if (g_strcasecmp(value, "one") == 0 ||
     190            g_strcasecmp(value, "many") == 0 || g_strcasecmp(value, "chat") == 0)
    201191                return value;
    202192        else
     
    204194}
    205195
    206 static gboolean twitter_length_check( struct im_connection *ic, gchar *msg )
    207 {
    208         int max = set_getint( &ic->acc->set, "message_length" ), len;
    209        
    210         if( max == 0 || ( len = g_utf8_strlen( msg, -1 ) ) <= max )
     196static gboolean twitter_length_check(struct im_connection *ic, gchar * msg)
     197{
     198        int max = set_getint(&ic->acc->set, "message_length"), len;
     199
     200        if (max == 0 || (len = g_utf8_strlen(msg, -1)) <= max)
    211201                return TRUE;
    212        
    213         imcb_error( ic, "Maximum message length exceeded: %d > %d", len, max );
    214        
     202
     203        imcb_error(ic, "Maximum message length exceeded: %d > %d", len, max);
     204
    215205        return FALSE;
    216206}
    217207
    218 static void twitter_init( account_t *acc )
     208static void twitter_init(account_t * acc)
    219209{
    220210        set_t *s;
    221211        char *def_url;
    222212        char *def_oauth;
    223        
    224         if( strcmp( acc->prpl->name, "twitter" ) == 0 )
    225         {
     213
     214        if (strcmp(acc->prpl->name, "twitter") == 0) {
    226215                def_url = TWITTER_API_URL;
    227216                def_oauth = "true";
    228         }
    229         else /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */
    230         {
     217        } else {                /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */
     218
    231219                def_url = IDENTICA_API_URL;
    232220                def_oauth = "false";
    233221        }
    234        
    235         s = set_add( &acc->set, "auto_reply_timeout", "10800", set_eval_int, acc );
    236        
    237         s = set_add( &acc->set, "base_url", def_url, NULL, acc );
     222
     223        s = set_add(&acc->set, "auto_reply_timeout", "10800", set_eval_int, acc);
     224
     225        s = set_add(&acc->set, "base_url", def_url, NULL, acc);
    238226        s->flags |= ACC_SET_OFFLINE_ONLY;
    239        
    240         s = set_add( &acc->set, "commands", "true", set_eval_bool, acc );
    241        
    242         s = set_add( &acc->set, "message_length", "140", set_eval_int, acc );
    243        
    244         s = set_add( &acc->set, "mode", "chat", set_eval_mode, acc );
     227
     228        s = set_add(&acc->set, "commands", "true", set_eval_bool, acc);
     229
     230        s = set_add(&acc->set, "message_length", "140", set_eval_int, acc);
     231
     232        s = set_add(&acc->set, "mode", "chat", set_eval_mode, acc);
    245233        s->flags |= ACC_SET_OFFLINE_ONLY;
    246        
    247         s = set_add( &acc->set, "show_ids", "false", set_eval_bool, acc );
     234
     235        s = set_add(&acc->set, "show_ids", "false", set_eval_bool, acc);
    248236        s->flags |= ACC_SET_OFFLINE_ONLY;
    249        
    250         s = set_add( &acc->set, "oauth", def_oauth, set_eval_bool, acc );
     237
     238        s = set_add(&acc->set, "oauth", def_oauth, set_eval_bool, acc);
    251239}
    252240
     
    255243 * only save the user and pass to the twitter_data object.
    256244 */
    257 static void twitter_login( account_t *acc )
    258 {
    259         struct im_connection *ic = imcb_new( acc );
     245static void twitter_login(account_t * acc)
     246{
     247        struct im_connection *ic = imcb_new(acc);
    260248        struct twitter_data *td;
    261         char name[strlen(acc->user)+9];
     249        char name[strlen(acc->user) + 9];
    262250        url_t url;
    263 
    264         if( !url_set( &url, set_getstr( &ic->acc->set, "base_url" ) ) ||
    265             ( url.proto != PROTO_HTTP && url.proto != PROTO_HTTPS ) )
    266         {
    267                 imcb_error( ic, "Incorrect API base URL: %s", set_getstr( &ic->acc->set, "base_url" ) );
    268                 imc_logout( ic, FALSE );
     251        char *s;
     252       
     253        if (!url_set(&url, set_getstr(&ic->acc->set, "base_url")) ||
     254            (url.proto != PROTO_HTTP && url.proto != PROTO_HTTPS)) {
     255                imcb_error(ic, "Incorrect API base URL: %s", set_getstr(&ic->acc->set, "base_url"));
     256                imc_logout(ic, FALSE);
    269257                return;
    270258        }
    271        
    272         twitter_connections = g_slist_append( twitter_connections, ic );
    273         td = g_new0( struct twitter_data, 1 );
     259
     260        imcb_log(ic, "Connecting");
     261
     262        twitter_connections = g_slist_append(twitter_connections, ic);
     263        td = g_new0(struct twitter_data, 1);
    274264        ic->proto_data = td;
    275        
     265        td->user = g_strdup(acc->user);
     266
    276267        td->url_ssl = url.proto == PROTO_HTTPS;
    277268        td->url_port = url.port;
    278         td->url_host = g_strdup( url.host );
    279         if( strcmp( url.file, "/" ) != 0 )
    280                 td->url_path = g_strdup( url.file );
    281         else
    282                 td->url_path = g_strdup( "" );
    283         if( g_str_has_suffix( url.host, ".com" ) )
    284                 td->prefix = g_strndup( url.host, strlen( url.host ) - 4 );
    285         else
    286                 td->prefix = g_strdup( url.host );
     269        td->url_host = g_strdup(url.host);
     270        if (strcmp(url.file, "/") != 0)
     271                td->url_path = g_strdup(url.file);
     272        else {
     273                td->url_path = g_strdup("");
     274                if (g_str_has_suffix(url.host, "twitter.com"))
     275                        /* May fire for people who turned on HTTPS. */
     276                        imcb_error(ic, "Warning: Twitter requires a version number in API calls "
     277                                       "now. Try resetting the base_url account setting.");
     278        }
    287279       
    288         td->user = acc->user;
    289         if( strstr( acc->pass, "oauth_token=" ) )
    290                 td->oauth_info = oauth_from_string( acc->pass, get_oauth_service( ic ) );
     280        /* Hacky string mangling: Turn identi.ca into identi.ca and api.twitter.com
     281           into twitter, and try to be sensible if we get anything else. */
     282        td->prefix = g_strdup(url.host);
     283        if (g_str_has_suffix(td->prefix, ".com"))
     284                td->prefix[strlen(url.host) - 4] = '\0';
     285        if ((s = strrchr(td->prefix, '.')) && strlen(s) > 4) {
     286                /* If we have at least 3 chars after the last dot, cut off the rest.
     287                   (mostly a www/api prefix or sth) */
     288                s = g_strdup(s + 1);
     289                g_free(td->prefix);
     290                td->prefix = s;
     291        }
    291292       
    292         sprintf( name, "%s_%s", td->prefix, acc->user );
    293         imcb_add_buddy( ic, name, NULL );
    294         imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL );
    295        
    296         if( set_getbool( &acc->set, "show_ids" ) )
    297                 td->log = g_new0( struct twitter_log_data, TWITTER_LOG_LENGTH );
    298        
    299         imcb_log( ic, "Connecting" );
    300        
    301         twitter_login_finish( ic );
     293        if (strstr(acc->pass, "oauth_token="))
     294                td->oauth_info = oauth_from_string(acc->pass, get_oauth_service(ic));
     295
     296        sprintf(name, "%s_%s", td->prefix, acc->user);
     297        imcb_add_buddy(ic, name, NULL);
     298        imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL);
     299
     300        if (set_getbool(&acc->set, "show_ids"))
     301                td->log = g_new0(struct twitter_log_data, TWITTER_LOG_LENGTH);
     302
     303        twitter_login_finish(ic);
    302304}
    303305
     
    305307 * Logout method. Just free the twitter_data.
    306308 */
    307 static void twitter_logout( struct im_connection *ic )
     309static void twitter_logout(struct im_connection *ic)
    308310{
    309311        struct twitter_data *td = ic->proto_data;
    310        
     312
    311313        // Set the status to logged out.
    312         ic->flags &= ~ OPT_LOGGED_IN;
     314        ic->flags &= ~OPT_LOGGED_IN;
    313315
    314316        // Remove the main_loop function from the function queue.
    315317        b_event_remove(td->main_loop_id);
    316318
    317         if(td->home_timeline_gc)
     319        if (td->home_timeline_gc)
    318320                imcb_chat_free(td->home_timeline_gc);
    319321
    320         if( td )
    321         {
    322                 oauth_info_free( td->oauth_info );
    323                 g_free( td->prefix );
    324                 g_free( td->url_host );
    325                 g_free( td->url_path );
    326                 g_free( td->pass );
    327                 g_free( td->log );
    328                 g_free( td );
    329         }
    330 
    331         twitter_connections = g_slist_remove( twitter_connections, ic );
    332 }
    333 
    334 static void twitter_handle_command( struct im_connection *ic, char *message );
     322        if (td) {
     323                oauth_info_free(td->oauth_info);
     324                g_free(td->user);
     325                g_free(td->prefix);
     326                g_free(td->url_host);
     327                g_free(td->url_path);
     328                g_free(td->log);
     329                g_free(td);
     330        }
     331
     332        twitter_connections = g_slist_remove(twitter_connections, ic);
     333}
     334
     335static void twitter_handle_command(struct im_connection *ic, char *message);
    335336
    336337/**
    337338 *
    338339 */
    339 static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message, int away )
     340static int twitter_buddy_msg(struct im_connection *ic, char *who, char *message, int away)
    340341{
    341342        struct twitter_data *td = ic->proto_data;
    342         int plen = strlen( td->prefix );
    343        
     343        int plen = strlen(td->prefix);
     344
    344345        if (g_strncasecmp(who, td->prefix, plen) == 0 && who[plen] == '_' &&
    345             g_strcasecmp(who + plen + 1, ic->acc->user) == 0)
    346         {
    347                 if( set_getbool( &ic->acc->set, "oauth" ) &&
    348                     td->oauth_info && td->oauth_info->token == NULL )
    349                 {
    350                         char pin[strlen(message)+1], *s;
    351                        
    352                         strcpy( pin, message );
    353                         for( s = pin + sizeof( pin ) - 2; s > pin && isspace( *s ); s -- )
     346            g_strcasecmp(who + plen + 1, ic->acc->user) == 0) {
     347                if (set_getbool(&ic->acc->set, "oauth") &&
     348                    td->oauth_info && td->oauth_info->token == NULL) {
     349                        char pin[strlen(message) + 1], *s;
     350
     351                        strcpy(pin, message);
     352                        for (s = pin + sizeof(pin) - 2; s > pin && isspace(*s); s--)
    354353                                *s = '\0';
    355                         for( s = pin; *s && isspace( *s ); s ++ ) {}
    356                        
    357                         if( !oauth_access_token( s, td->oauth_info ) )
    358                         {
    359                                 imcb_error( ic, "OAuth error: %s", "Failed to send access token request" );
    360                                 imc_logout( ic, TRUE );
     354                        for (s = pin; *s && isspace(*s); s++) {
     355                        }
     356
     357                        if (!oauth_access_token(s, td->oauth_info)) {
     358                                imcb_error(ic, "OAuth error: %s",
     359                                           "Failed to send access token request");
     360                                imc_logout(ic, TRUE);
    361361                                return FALSE;
    362362                        }
    363                 }
    364                 else
     363                } else
    365364                        twitter_handle_command(ic, message);
    366         }
    367         else
    368         {
     365        } else {
    369366                twitter_direct_messages_new(ic, who, message);
    370367        }
    371         return( 0 );
     368        return (0);
    372369}
    373370
     
    375372 *
    376373 */
    377 static void twitter_set_my_name( struct im_connection *ic, char *info )
    378 {
    379 }
    380 
    381 static void twitter_get_info(struct im_connection *ic, char *who) 
    382 {
    383 }
    384 
    385 static void twitter_add_buddy( struct im_connection *ic, char *who, char *group )
     374static void twitter_set_my_name(struct im_connection *ic, char *info)
     375{
     376}
     377
     378static void twitter_get_info(struct im_connection *ic, char *who)
     379{
     380}
     381
     382static void twitter_add_buddy(struct im_connection *ic, char *who, char *group)
    386383{
    387384        twitter_friendships_create_destroy(ic, who, 1);
    388385}
    389386
    390 static void twitter_remove_buddy( struct im_connection *ic, char *who, char *group )
     387static void twitter_remove_buddy(struct im_connection *ic, char *who, char *group)
    391388{
    392389        twitter_friendships_create_destroy(ic, who, 0);
    393390}
    394391
    395 static void twitter_chat_msg( struct groupchat *c, char *message, int flags )
    396 {
    397         if( c && message )
    398                 twitter_handle_command( c->ic, message );
    399 }
    400 
    401 static void twitter_chat_invite( struct groupchat *c, char *who, char *message )
    402 {
    403 }
    404 
    405 static void twitter_chat_leave( struct groupchat *c )
     392static void twitter_chat_msg(struct groupchat *c, char *message, int flags)
     393{
     394        if (c && message)
     395                twitter_handle_command(c->ic, message);
     396}
     397
     398static void twitter_chat_invite(struct groupchat *c, char *who, char *message)
     399{
     400}
     401
     402static void twitter_chat_leave(struct groupchat *c)
    406403{
    407404        struct twitter_data *td = c->ic->proto_data;
    408        
    409         if( c != td->home_timeline_gc )
    410                 return; /* WTF? */
    411        
     405
     406        if (c != td->home_timeline_gc)
     407                return;         /* WTF? */
     408
    412409        /* If the user leaves the channel: Fine. Rejoin him/her once new
    413410           tweets come in. */
     
    416413}
    417414
    418 static void twitter_keepalive( struct im_connection *ic )
    419 {
    420 }
    421 
    422 static void twitter_add_permit( struct im_connection *ic, char *who )
    423 {
    424 }
    425 
    426 static void twitter_rem_permit( struct im_connection *ic, char *who )
    427 {
    428 }
    429 
    430 static void twitter_add_deny( struct im_connection *ic, char *who )
    431 {
    432 }
    433 
    434 static void twitter_rem_deny( struct im_connection *ic, char *who )
     415static void twitter_keepalive(struct im_connection *ic)
     416{
     417}
     418
     419static void twitter_add_permit(struct im_connection *ic, char *who)
     420{
     421}
     422
     423static void twitter_rem_permit(struct im_connection *ic, char *who)
     424{
     425}
     426
     427static void twitter_add_deny(struct im_connection *ic, char *who)
     428{
     429}
     430
     431static void twitter_rem_deny(struct im_connection *ic, char *who)
    435432{
    436433}
     
    438435//static char *twitter_set_display_name( set_t *set, char *value )
    439436//{
    440 //      return value;
     437//      return value;
    441438//}
    442439
    443 static void twitter_buddy_data_add( struct bee_user *bu )
    444 {
    445         bu->data = g_new0( struct twitter_user_data, 1 );
    446 }
    447 
    448 static void twitter_buddy_data_free( struct bee_user *bu )
    449 {
    450         g_free( bu->data );
    451 }
    452 
    453 static void twitter_handle_command( struct im_connection *ic, char *message )
     440static void twitter_buddy_data_add(struct bee_user *bu)
     441{
     442        bu->data = g_new0(struct twitter_user_data, 1);
     443}
     444
     445static void twitter_buddy_data_free(struct bee_user *bu)
     446{
     447        g_free(bu->data);
     448}
     449
     450static void twitter_handle_command(struct im_connection *ic, char *message)
    454451{
    455452        struct twitter_data *td = ic->proto_data;
    456453        char *cmds, **cmd, *new = NULL;
    457454        guint64 in_reply_to = 0;
    458        
    459         cmds = g_strdup( message );
    460         cmd = split_command_parts( cmds );
    461        
    462         if( cmd[0] == NULL )
    463         {
    464                 g_free( cmds );
     455
     456        cmds = g_strdup(message);
     457        cmd = split_command_parts(cmds);
     458
     459        if (cmd[0] == NULL) {
     460                g_free(cmds);
    465461                return;
    466         }
    467         else if( !set_getbool( &ic->acc->set, "commands" ) )
    468         {
     462        } else if (!set_getbool(&ic->acc->set, "commands")) {
    469463                /* Not supporting commands. */
    470         }
    471         else if( g_strcasecmp( cmd[0], "undo" ) == 0 )
    472         {
     464        } else if (g_strcasecmp(cmd[0], "undo") == 0) {
    473465                guint64 id;
    474                
    475                 if( cmd[1] )
    476                         id = g_ascii_strtoull( cmd[1], NULL, 10 );
     466
     467                if (cmd[1])
     468                        id = g_ascii_strtoull(cmd[1], NULL, 10);
    477469                else
    478470                        id = td->last_status_id;
    479                
     471
    480472                /* TODO: User feedback. */
    481                 if( id )
    482                         twitter_status_destroy( ic, id );
     473                if (id)
     474                        twitter_status_destroy(ic, id);
    483475                else
    484                         twitter_msg( ic, "Could not undo last action" );
    485                
    486                 g_free( cmds );
     476                        twitter_msg(ic, "Could not undo last action");
     477
     478                g_free(cmds);
    487479                return;
    488         }
    489         else if( g_strcasecmp( cmd[0], "follow" ) == 0 && cmd[1] )
    490         {
    491                 twitter_add_buddy( ic, cmd[1], NULL );
    492                 g_free( cmds );
     480        } else if (g_strcasecmp(cmd[0], "follow") == 0 && cmd[1]) {
     481                twitter_add_buddy(ic, cmd[1], NULL);
     482                g_free(cmds);
    493483                return;
    494         }
    495         else if( g_strcasecmp( cmd[0], "unfollow" ) == 0 && cmd[1] )
    496         {
    497                 twitter_remove_buddy( ic, cmd[1], NULL );
    498                 g_free( cmds );
     484        } else if (g_strcasecmp(cmd[0], "unfollow") == 0 && cmd[1]) {
     485                twitter_remove_buddy(ic, cmd[1], NULL);
     486                g_free(cmds);
    499487                return;
    500         }
    501         else if( g_strcasecmp( cmd[0], "rt" ) == 0 && cmd[1] )
    502         {
     488        } else if (g_strcasecmp(cmd[0], "rt") == 0 && cmd[1]) {
    503489                struct twitter_user_data *tud;
    504490                bee_user_t *bu;
    505491                guint64 id;
    506                
    507                 if( ( bu = bee_user_by_handle( ic->bee, ic, cmd[1] ) ) &&
    508                     ( tud = bu->data ) && tud->last_id )
     492
     493                if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) &&
     494                    (tud = bu->data) && tud->last_id)
    509495                        id = tud->last_id;
    510                 else
    511                 {
    512                         id = g_ascii_strtoull( cmd[1], NULL, 10 );
    513                         if( id < TWITTER_LOG_LENGTH && td->log )
     496                else {
     497                        id = g_ascii_strtoull(cmd[1], NULL, 10);
     498                        if (id < TWITTER_LOG_LENGTH && td->log)
    514499                                id = td->log[id].id;
    515500                }
    516                
     501
    517502                td->last_status_id = 0;
    518                 if( id )
    519                         twitter_status_retweet( ic, id );
     503                if (id)
     504                        twitter_status_retweet(ic, id);
    520505                else
    521                         twitter_msg( ic, "User `%s' does not exist or didn't "
    522                                          "post any statuses recently", cmd[1] );
    523                
    524                 g_free( cmds );
     506                        twitter_msg(ic, "User `%s' does not exist or didn't "
     507                                    "post any statuses recently", cmd[1]);
     508
     509                g_free(cmds);
    525510                return;
    526         }
    527         else if( g_strcasecmp( cmd[0], "reply" ) == 0 && cmd[1] && cmd[2] )
    528         {
     511        } else if (g_strcasecmp(cmd[0], "reply") == 0 && cmd[1] && cmd[2]) {
    529512                struct twitter_user_data *tud;
    530513                bee_user_t *bu = NULL;
    531514                guint64 id = 0;
    532                
    533                 if( ( bu = bee_user_by_handle( ic->bee, ic, cmd[1] ) ) &&
    534                     ( tud = bu->data ) && tud->last_id )
    535                 {
     515
     516                if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) &&
     517                    (tud = bu->data) && tud->last_id) {
    536518                        id = tud->last_id;
    537                 }
    538                 else if( ( id = g_ascii_strtoull( cmd[1], NULL, 10 ) ) &&
    539                          ( id < TWITTER_LOG_LENGTH ) && td->log )
    540                 {
     519                } else if (sscanf(cmd[1], "%" G_GUINT64_FORMAT, &id) == 1 &&
     520                           (id < TWITTER_LOG_LENGTH) && td->log) {
    541521                        bu = td->log[id].bu;
    542                         if( g_slist_find( ic->bee->users, bu ) )
     522                        if (g_slist_find(ic->bee->users, bu))
    543523                                id = td->log[id].id;
    544524                        else
    545525                                bu = NULL;
    546526                }
    547                 if( !id || !bu )
    548                 {
    549                         twitter_msg( ic, "User `%s' does not exist or didn't "
    550                                          "post any statuses recently", cmd[1] );
     527                if (!id || !bu) {
     528                        twitter_msg(ic, "User `%s' does not exist or didn't "
     529                                    "post any statuses recently", cmd[1]);
    551530                        return;
    552531                }
    553                 message = new = g_strdup_printf( "@%s %s", bu->handle,
    554                                                  message + ( cmd[2] - cmd[0] ) );
     532                message = new = g_strdup_printf("@%s %s", bu->handle, message + (cmd[2] - cmd[0]));
    555533                in_reply_to = id;
    556         }
    557         else if( g_strcasecmp( cmd[0], "post" ) == 0 )
    558         {
     534        } else if (g_strcasecmp(cmd[0], "post") == 0) {
    559535                message += 5;
    560536        }
    561        
     537
    562538        {
    563539                char *s;
    564540                bee_user_t *bu;
    565                
    566                 if( !twitter_length_check( ic, message ) )
    567                 {
    568                         g_free( new );
    569                         g_free( cmds );
    570                         return;
     541
     542                if (!twitter_length_check(ic, message)) {
     543                        g_free(new);
     544                        g_free(cmds);
     545                        return;
    571546                }
    572                
    573                 s = cmd[0] + strlen( cmd[0] ) - 1;
    574                 if( !new && s > cmd[0] && ( *s == ':' || *s == ',' ) )
    575                 {
     547
     548                s = cmd[0] + strlen(cmd[0]) - 1;
     549                if (!new && s > cmd[0] && (*s == ':' || *s == ',')) {
    576550                        *s = '\0';
    577                        
    578                         if( ( bu = bee_user_by_handle( ic->bee, ic, cmd[0] ) ) )
    579                         {
     551
     552                        if ((bu = bee_user_by_handle(ic->bee, ic, cmd[0]))) {
    580553                                struct twitter_user_data *tud = bu->data;
    581                                
    582                                 new = g_strdup_printf( "@%s %s", bu->handle,
    583                                                        message + ( s - cmd[0] ) + 2 );
     554
     555                                new = g_strdup_printf("@%s %s", bu->handle,
     556                                                      message + (s - cmd[0]) + 2);
    584557                                message = new;
    585                                
    586                                 if( time( NULL ) < tud->last_time +
    587                                     set_getint( &ic->acc->set, "auto_reply_timeout" ) )
     558
     559                                if (time(NULL) < tud->last_time +
     560                                    set_getint(&ic->acc->set, "auto_reply_timeout"))
    588561                                        in_reply_to = tud->last_id;
    589562                        }
    590563                }
    591                
     564
    592565                /* If the user runs undo between this request and its response
    593566                   this would delete the second-last Tweet. Prevent that. */
    594567                td->last_status_id = 0;
    595                 twitter_post_status( ic, message, in_reply_to );
    596                 g_free( new );
    597         }
    598         g_free( cmds );
     568                twitter_post_status(ic, message, in_reply_to);
     569                g_free(new);
     570        }
     571        g_free(cmds);
    599572}
    600573
     
    602575{
    603576        struct prpl *ret = g_new0(struct prpl, 1);
    604        
     577
    605578        ret->options = OPT_NOOTR;
    606579        ret->name = "twitter";
     
    624597        ret->buddy_data_free = twitter_buddy_data_free;
    625598        ret->handle_cmp = g_strcasecmp;
    626        
     599
    627600        register_protocol(ret);
    628601
  • protocols/twitter/twitter.h

    r17f6079 rc8b8c83  
    4343{
    4444        char* user;
    45         char* pass;
    4645        struct oauth_info *oauth_info;
     46        GSList *follow_ids;
     47       
    4748        guint64 home_timeline_id;
    4849        guint64 last_status_id; /* For undo */
     
    5253        twitter_flags_t flags;
    5354       
     55        /* set base_url */
    5456        gboolean url_ssl;
    5557        int url_port;
     
    5961        char *prefix; /* Used to generate contact + channel name. */
    6062       
     63        /* set show_ids */
    6164        struct twitter_log_data *log;
    6265        int log_id;
     
    8588void twitter_login_finish( struct im_connection *ic );
    8689
     90struct http_request;
     91char *twitter_parse_error( struct http_request *req );
     92
    8793#endif //_TWITTER_H
  • protocols/twitter/twitter_http.c

    r17f6079 rc8b8c83  
    2727*  BitlBee.                                                                 *
    2828*                                                                           *
    29 ****************************************************************************/ 
     29****************************************************************************/
    3030
    3131#include "twitter.h"
     
    4141
    4242
    43 static char *twitter_url_append(char *url, char *key, char* value);
     43static char *twitter_url_append(char *url, char *key, char *value);
    4444
    4545/**
     
    4747 * This is actually pretty generic function... Perhaps it should move to the lib/http_client.c
    4848 */
    49 void *twitter_http(struct im_connection *ic, char *url_string, http_input_function func, gpointer data, int is_post, char** arguments, int arguments_len)
     49void *twitter_http(struct im_connection *ic, char *url_string, http_input_function func,
     50                   gpointer data, int is_post, char **arguments, int arguments_len)
    5051{
    5152        struct twitter_data *td = ic->proto_data;
     
    5859
    5960        // Construct the url arguments.
    60         if (arguments_len != 0)
    61         {
     61        if (arguments_len != 0) {
    6262                int i;
    63                 for (i=0; i<arguments_len; i+=2)
    64                 {
    65                         tmp = twitter_url_append(url_arguments, arguments[i], arguments[i+1]);
     63                for (i = 0; i < arguments_len; i += 2) {
     64                        tmp = twitter_url_append(url_arguments, arguments[i], arguments[i + 1]);
    6665                        g_free(url_arguments);
    6766                        url_arguments = tmp;
    6867                }
    6968        }
    70 
    7169        // Make the request.
    7270        g_string_printf(request, "%s %s%s%s%s HTTP/1.0\r\n"
    73                                  "Host: %s\r\n"
    74                                  "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",
    75                                  is_post ? "POST" : "GET",
    76                                  td->url_path, url_string,
    77                                  is_post ? "" : "?", is_post ? "" : url_arguments,
    78                                  td->url_host);
     71                        "Host: %s\r\n"
     72                        "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",
     73                        is_post ? "POST" : "GET",
     74                        td->url_path, url_string,
     75                        is_post ? "" : "?", is_post ? "" : url_arguments, td->url_host);
    7976
    8077        // If a pass and user are given we append them to the request.
    81         if (td->oauth_info)
    82         {
     78        if (td->oauth_info) {
    8379                char *full_header;
    8480                char *full_url;
    85                
    86                 full_url = g_strconcat(set_getstr(&ic->acc->set, "base_url" ), url_string, NULL);
     81
     82                full_url = g_strconcat(set_getstr(&ic->acc->set, "base_url"), url_string, NULL);
    8783                full_header = oauth_http_header(td->oauth_info, is_post ? "POST" : "GET",
    88                                                 full_url, url_arguments);
    89                
     84                                                full_url, url_arguments);
     85
    9086                g_string_append_printf(request, "Authorization: %s\r\n", full_header);
    9187                g_free(full_header);
    9288                g_free(full_url);
    93         }
    94         else
    95         {
    96                 char userpass[strlen(ic->acc->user)+2+strlen(ic->acc->pass)];
     89        } else {
     90                char userpass[strlen(ic->acc->user) + 2 + strlen(ic->acc->pass)];
    9791                char *userpass_base64;
    98                
     92
    9993                g_snprintf(userpass, sizeof(userpass), "%s:%s", ic->acc->user, ic->acc->pass);
    100                 userpass_base64 = base64_encode((unsigned char*)userpass, strlen(userpass));
     94                userpass_base64 = base64_encode((unsigned char *) userpass, strlen(userpass));
    10195                g_string_append_printf(request, "Authorization: Basic %s\r\n", userpass_base64);
    102                 g_free( userpass_base64 );
     96                g_free(userpass_base64);
    10397        }
    10498
    10599        // Do POST stuff..
    106         if (is_post)
    107         {
     100        if (is_post) {
    108101                // Append the Content-Type and url-encoded arguments.
    109102                g_string_append_printf(request,
    110                                        "Content-Type: application/x-www-form-urlencoded\r\n"
    111                                        "Content-Length: %zd\r\n\r\n%s",
    112                                        strlen(url_arguments), url_arguments);
     103                                       "Content-Type: application/x-www-form-urlencoded\r\n"
     104                                       "Content-Length: %zd\r\n\r\n%s",
     105                                       strlen(url_arguments), url_arguments);
    113106        } else {
    114107                // Append an extra \r\n to end the request...
     
    118111        ret = http_dorequest(td->url_host, td->url_port, td->url_ssl, request->str, func, data);
    119112
    120         g_free( url_arguments );
    121         g_string_free( request, TRUE );
     113        g_free(url_arguments);
     114        g_string_free(request, TRUE);
    122115        return ret;
    123116}
    124117
    125 static char *twitter_url_append(char *url, char *key, char* value)
     118static char *twitter_url_append(char *url, char *key, char *value)
    126119{
    127120        char *key_encoded = g_strndup(key, 3 * strlen(key));
  • protocols/twitter/twitter_lib.c

    r17f6079 rc8b8c83  
    5555        gint64 next_cursor;
    5656        GSList *list;
    57         gpointer data;
    5857};
    5958
     
    104103        if (txl == NULL)
    105104                return;
    106         for ( l = txl->list; l ; l = g_slist_next(l) )
     105        for (l = txl->list; l; l = g_slist_next(l))
    107106                if (txl->type == TXL_STATUS)
    108                         txs_free((struct twitter_xml_status *)l->data);
     107                        txs_free((struct twitter_xml_status *) l->data);
    109108                else if (txl->type == TXL_ID)
    110109                        g_free(l->data);
     110                else if (txl->type == TXL_USER)
     111                        txu_free(l->data);
    111112        g_slist_free(txl->list);
    112113        g_free(txl);
     
    120121        struct twitter_data *td = ic->proto_data;
    121122
    122         // Check if the buddy is allready in the buddy list.
    123         if (!bee_user_by_handle( ic->bee, ic, name ))
    124         {
     123        // Check if the buddy is already in the buddy list.
     124        if (!bee_user_by_handle(ic->bee, ic, name)) {
    125125                char *mode = set_getstr(&ic->acc->set, "mode");
    126                
     126
    127127                // The buddy is not in the list, add the buddy and set the status to logged in.
    128                 imcb_add_buddy( ic, name, NULL );
    129                 imcb_rename_buddy( ic, name, fullname );
    130                 if (g_strcasecmp(mode, "chat") == 0)
    131                 {
     128                imcb_add_buddy(ic, name, NULL);
     129                imcb_rename_buddy(ic, name, fullname);
     130                if (g_strcasecmp(mode, "chat") == 0) {
    132131                        /* Necessary so that nicks always get translated to the
    133132                           exact Twitter username. */
    134                         imcb_buddy_nick_hint( ic, name, name );
    135                         imcb_chat_add_buddy( td->home_timeline_gc, name );
    136                 }
    137                 else if (g_strcasecmp(mode, "many") == 0)
    138                         imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL );
     133                        imcb_buddy_nick_hint(ic, name, name);
     134                        imcb_chat_add_buddy(td->home_timeline_gc, name);
     135                } else if (g_strcasecmp(mode, "many") == 0)
     136                        imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL);
    139137        }
    140138}
    141139
    142140/* Warning: May return a malloc()ed value, which will be free()d on the next
    143    call. Only for short-term use. */
    144 static char *twitter_parse_error(struct http_request *req)
     141   call. Only for short-term use. NOT THREADSAFE!  */
     142char *twitter_parse_error(struct http_request *req)
    145143{
    146144        static char *ret = NULL;
    147145        struct xt_parser *xp = NULL;
    148         struct xt_node *node;
    149        
     146        struct xt_node *node, *err;
     147
    150148        g_free(ret);
    151149        ret = NULL;
    152        
    153         if (req->body_size > 0)
    154         {
     150
     151        if (req->body_size > 0) {
    155152                xp = xt_new(NULL, NULL);
    156153                xt_feed(xp, req->reply_body, req->body_size);
    157154               
    158                 if ((node = xt_find_node(xp->root, "hash")) &&
    159                     (node = xt_find_node(node->children, "error")) &&
    160                     node->text_len > 0)
    161                 {
    162                         ret = g_strdup_printf("%s (%s)", req->status_string, node->text);
    163                         xt_free(xp);
    164                         return ret;
    165                 }
    166                
     155                for (node = xp->root; node; node = node->next)
     156                        if ((err = xt_find_node(node->children, "error")) && err->text_len > 0) {
     157                                ret = g_strdup_printf("%s (%s)", req->status_string, err->text);
     158                                break;
     159                        }
     160
    167161                xt_free(xp);
    168162        }
    169        
    170         return req->status_string;
     163
     164        return ret ? ret : req->status_string;
    171165}
    172166
     
    178172void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor)
    179173{
    180         // Primitive, but hey! It works...     
    181         char* args[2];
     174        // Primitive, but hey! It works...     
     175        char *args[2];
    182176        args[0] = "cursor";
    183         args[1] = g_strdup_printf ("%lld", (long long) next_cursor);
     177        args[1] = g_strdup_printf("%lld", (long long) next_cursor);
    184178        twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2);
    185179
     
    190184 * Function to help fill a list.
    191185 */
    192 static xt_status twitter_xt_next_cursor( struct xt_node *node, struct twitter_xml_list *txl )
     186static xt_status twitter_xt_next_cursor(struct xt_node *node, struct twitter_xml_list *txl)
    193187{
    194188        char *end = NULL;
    195        
    196         if( node->text )
    197                 txl->next_cursor = g_ascii_strtoll( node->text, &end, 10 );
    198         if( end == NULL )
     189
     190        if (node->text)
     191                txl->next_cursor = g_ascii_strtoll(node->text, &end, 10);
     192        if (end == NULL)
    199193                txl->next_cursor = -1;
    200194
     
    205199 * Fill a list of ids.
    206200 */
    207 static xt_status twitter_xt_get_friends_id_list( struct xt_node *node, struct twitter_xml_list *txl )
     201static xt_status twitter_xt_get_friends_id_list(struct xt_node *node, struct twitter_xml_list *txl)
    208202{
    209203        struct xt_node *child;
    210        
     204
    211205        // Set the list type.
    212206        txl->type = TXL_ID;
     
    214208        // The root <statuses> node should hold the list of statuses <status>
    215209        // Walk over the nodes children.
    216         for( child = node->children ; child ; child = child->next )
    217         {
    218                 if ( g_strcasecmp( "id", child->name ) == 0)
    219                 {
    220                         // Add the item to the list.
    221                         txl->list = g_slist_append (txl->list, g_memdup( child->text, child->text_len + 1 ));
    222                 }
    223                 else if ( g_strcasecmp( "next_cursor", child->name ) == 0)
    224                 {
     210        for (child = node->children; child; child = child->next) {
     211                if (g_strcasecmp("ids", child->name) == 0) {
     212                        struct xt_node *idc;
     213                        for (idc = child->children; idc; idc = idc->next)
     214                                if (g_strcasecmp(idc->name, "id") == 0)
     215                                        txl->list = g_slist_prepend(txl->list,
     216                                                g_memdup(idc->text, idc->text_len + 1));
     217                } else if (g_strcasecmp("next_cursor", child->name) == 0) {
    225218                        twitter_xt_next_cursor(child, txl);
    226219                }
     
    229222        return XT_HANDLED;
    230223}
     224
     225static void twitter_get_users_lookup(struct im_connection *ic);
    231226
    232227/**
     
    243238
    244239        // Check if the connection is still active.
    245         if( !g_slist_find( twitter_connections, ic ) )
    246                 return;
     240        if (!g_slist_find(twitter_connections, ic))
     241                return;
     242
     243        td = ic->proto_data;
     244
     245        // Check if the HTTP request went well. More strict checks as this is
     246        // the first request we do in a session.
     247        if (req->status_code == 401) {
     248                imcb_error(ic, "Authentication failure");
     249                imc_logout(ic, FALSE);
     250                return;
     251        } else if (req->status_code != 200) {
     252                // It didn't go well, output the error and return.
     253                imcb_error(ic, "Could not retrieve %s: %s",
     254                           TWITTER_FRIENDS_IDS_URL, twitter_parse_error(req));
     255                imc_logout(ic, TRUE);
     256                return;
     257        } else {
     258                td->http_fails = 0;
     259        }
     260
     261        /* Create the room now that we "logged in". */
     262        if (!td->home_timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
     263                twitter_groupchat_init(ic);
     264
     265        txl = g_new0(struct twitter_xml_list, 1);
     266        txl->list = td->follow_ids;
     267
     268        // Parse the data.
     269        parser = xt_new(NULL, txl);
     270        xt_feed(parser, req->reply_body, req->body_size);
     271        twitter_xt_get_friends_id_list(parser->root, txl);
     272        xt_free(parser);
     273
     274        td->follow_ids = txl->list;
     275        if (txl->next_cursor)
     276                /* These were just numbers. Up to 4000 in a response AFAIK so if we get here
     277                   we may be using a spammer account. \o/ */
     278                twitter_get_friends_ids(ic, txl->next_cursor);
     279        else
     280                /* Now to convert all those numbers into names.. */
     281                twitter_get_users_lookup(ic);
     282
     283        txl->list = NULL;
     284        txl_free(txl);
     285}
     286
     287static xt_status twitter_xt_get_users(struct xt_node *node, struct twitter_xml_list *txl);
     288static void twitter_http_get_users_lookup(struct http_request *req);
     289
     290static void twitter_get_users_lookup(struct im_connection *ic)
     291{
     292        struct twitter_data *td = ic->proto_data;
     293        char *args[2] = {
     294                "user_id",
     295                NULL,
     296        };
     297        GString *ids = g_string_new("");
     298        int i;
    247299       
     300        /* We can request up to 100 users at a time. */
     301        for (i = 0; i < 100 && td->follow_ids; i ++) {
     302                g_string_append_printf(ids, ",%s", (char*) td->follow_ids->data);
     303                g_free(td->follow_ids->data);
     304                td->follow_ids = g_slist_remove(td->follow_ids, td->follow_ids->data);
     305        }
     306        if (ids->len > 0) {
     307                args[1] = ids->str + 1;
     308                /* POST, because I think ids can be up to 1KB long. */
     309                twitter_http(ic, TWITTER_USERS_LOOKUP_URL, twitter_http_get_users_lookup, ic, 1, args, 2);
     310        } else {
     311                /* We have all users. Continue with login. (Get statuses.) */
     312                td->flags |= TWITTER_HAVE_FRIENDS;
     313                twitter_login_finish(ic);
     314        }
     315        g_string_free(ids, TRUE);
     316}
     317
     318/**
     319 * Callback for getting (twitter)friends...
     320 *
     321 * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has
     322 * hundreds of friends?" you wonder? You probably not, since you are reading the source of
     323 * BitlBee... Get a life and meet new people!
     324 */
     325static void twitter_http_get_users_lookup(struct http_request *req)
     326{
     327        struct im_connection *ic = req->data;
     328        struct twitter_data *td;
     329        struct xt_parser *parser;
     330        struct twitter_xml_list *txl;
     331        GSList *l = NULL;
     332        struct twitter_xml_user *user;
     333
     334        // Check if the connection is still active.
     335        if (!g_slist_find(twitter_connections, ic))
     336                return;
     337
    248338        td = ic->proto_data;
    249339
    250         // Check if the HTTP request went well.
    251340        if (req->status_code != 200) {
    252341                // It didn't go well, output the error and return.
    253                 if (++td->http_fails >= 5)
    254                         imcb_error(ic, "Could not retrieve friends: %s", twitter_parse_error(req));
    255                
     342                imcb_error(ic, "Could not retrieve %s: %s",
     343                           TWITTER_USERS_LOOKUP_URL, twitter_parse_error(req));
     344                imc_logout(ic, TRUE);
    256345                return;
    257346        } else {
     
    260349
    261350        txl = g_new0(struct twitter_xml_list, 1);
     351        txl->list = NULL;
    262352
    263353        // Parse the data.
    264         parser = xt_new( NULL, txl );
    265         xt_feed( parser, req->reply_body, req->body_size );
    266         twitter_xt_get_friends_id_list(parser->root, txl);
    267         xt_free( parser );
    268 
    269         if (txl->next_cursor)
    270                 twitter_get_friends_ids(ic, txl->next_cursor);
    271 
     354        parser = xt_new(NULL, txl);
     355        xt_feed(parser, req->reply_body, req->body_size);
     356
     357        // Get the user list from the parsed xml feed.
     358        twitter_xt_get_users(parser->root, txl);
     359        xt_free(parser);
     360
     361        // Add the users as buddies.
     362        for (l = txl->list; l; l = g_slist_next(l)) {
     363                user = l->data;
     364                twitter_add_buddy(ic, user->screen_name, user->name);
     365        }
     366
     367        // Free the structure.
    272368        txl_free(txl);
     369
     370        twitter_get_users_lookup(ic);
    273371}
    274372
     
    279377 *  - the screen_name.
    280378 */
    281 static xt_status twitter_xt_get_user( struct xt_node *node, struct twitter_xml_user *txu )
     379static xt_status twitter_xt_get_user(struct xt_node *node, struct twitter_xml_user *txu)
    282380{
    283381        struct xt_node *child;
    284382
    285383        // Walk over the nodes children.
    286         for( child = node->children ; child ; child = child->next )
    287         {
    288                 if ( g_strcasecmp( "name", child->name ) == 0)
    289                 {
    290                         txu->name = g_memdup( child->text, child->text_len + 1 );
    291                 }
    292                 else if (g_strcasecmp( "screen_name", child->name ) == 0)
    293                 {
    294                         txu->screen_name = g_memdup( child->text, child->text_len + 1 );
     384        for (child = node->children; child; child = child->next) {
     385                if (g_strcasecmp("name", child->name) == 0) {
     386                        txu->name = g_memdup(child->text, child->text_len + 1);
     387                } else if (g_strcasecmp("screen_name", child->name) == 0) {
     388                        txu->screen_name = g_memdup(child->text, child->text_len + 1);
    295389                }
    296390        }
     
    303397 *  - all <user>s from the <users> element.
    304398 */
    305 static xt_status twitter_xt_get_users( struct xt_node *node, struct twitter_xml_list *txl )
     399static xt_status twitter_xt_get_users(struct xt_node *node, struct twitter_xml_list *txl)
    306400{
    307401        struct twitter_xml_user *txu;
     
    313407        // The root <users> node should hold the list of users <user>
    314408        // Walk over the nodes children.
    315         for( child = node->children ; child ; child = child->next )
    316         {
    317                 if ( g_strcasecmp( "user", child->name ) == 0)
    318                 {
     409        for (child = node->children; child; child = child->next) {
     410                if (g_strcasecmp("user", child->name) == 0) {
    319411                        txu = g_new0(struct twitter_xml_user, 1);
    320412                        twitter_xt_get_user(child, txu);
    321413                        // Put the item in the front of the list.
    322                         txl->list = g_slist_prepend (txl->list, txu);
    323                 }
    324         }
    325 
    326         return XT_HANDLED;
    327 }
    328 
    329 /**
    330  * Function to fill a twitter_xml_list struct.
    331  * It calls twitter_xt_get_users to get the <user>s from a <users> element.
    332  * It sets:
    333  *  - the next_cursor.
    334  */
    335 static xt_status twitter_xt_get_user_list( struct xt_node *node, struct twitter_xml_list *txl )
    336 {
    337         struct xt_node *child;
    338 
    339         // Set the type of the list.
    340         txl->type = TXL_USER;
    341 
    342         // The root <user_list> node should hold a users <users> element
    343         // Walk over the nodes children.
    344         for( child = node->children ; child ; child = child->next )
    345         {
    346                 if ( g_strcasecmp( "users", child->name ) == 0)
    347                 {
    348                         twitter_xt_get_users(child, txl);
    349                 }
    350                 else if ( g_strcasecmp( "next_cursor", child->name ) == 0)
    351                 {
    352                         twitter_xt_next_cursor(child, txl);
     414                        txl->list = g_slist_prepend(txl->list, txu);
    353415                }
    354416        }
     
    371433 *  - the user in a twitter_xml_user struct.
    372434 */
    373 static xt_status twitter_xt_get_status( struct xt_node *node, struct twitter_xml_status *txs )
     435static xt_status twitter_xt_get_status(struct xt_node *node, struct twitter_xml_status *txs)
    374436{
    375437        struct xt_node *child, *rt = NULL;
     
    377439
    378440        // Walk over the nodes children.
    379         for( child = node->children ; child ; child = child->next )
    380         {
    381                 if ( g_strcasecmp( "text", child->name ) == 0)
    382                 {
    383                         txs->text = g_memdup( child->text, child->text_len + 1 );
    384                 }
    385                 else if (g_strcasecmp( "truncated", child->name ) == 0 && child->text)
    386                 {
     441        for (child = node->children; child; child = child->next) {
     442                if (g_strcasecmp("text", child->name) == 0) {
     443                        txs->text = g_memdup(child->text, child->text_len + 1);
     444                } else if (g_strcasecmp("truncated", child->name) == 0 && child->text) {
    387445                        truncated = bool2int(child->text);
    388                 }
    389                 else if (g_strcasecmp( "retweeted_status", child->name ) == 0)
    390                 {
     446                } else if (g_strcasecmp("retweeted_status", child->name) == 0) {
    391447                        rt = child;
    392                 }
    393                 else if (g_strcasecmp( "created_at", child->name ) == 0)
    394                 {
     448                } else if (g_strcasecmp("created_at", child->name) == 0) {
    395449                        struct tm parsed;
    396                        
     450
    397451                        /* Very sensitive to changes to the formatting of
    398452                           this field. :-( Also assumes the timezone used
    399453                           is UTC since C time handling functions suck. */
    400                         if( strptime( child->text, TWITTER_TIME_FORMAT, &parsed ) != NULL )
    401                                 txs->created_at = mktime_utc( &parsed );
     454                        if (strptime(child->text, TWITTER_TIME_FORMAT, &parsed) != NULL)
     455                                txs->created_at = mktime_utc(&parsed);
     456                } else if (g_strcasecmp("user", child->name) == 0) {
     457                        txs->user = g_new0(struct twitter_xml_user, 1);
     458                        twitter_xt_get_user(child, txs->user);
     459                } else if (g_strcasecmp("id", child->name) == 0) {
     460                        txs->id = g_ascii_strtoull(child->text, NULL, 10);
     461                } else if (g_strcasecmp("in_reply_to_status_id", child->name) == 0) {
     462                        txs->reply_to = g_ascii_strtoull(child->text, NULL, 10);
    402463                }
    403                 else if (g_strcasecmp( "user", child->name ) == 0)
    404                 {
    405                         txs->user = g_new0(struct twitter_xml_user, 1);
    406                         twitter_xt_get_user( child, txs->user );
    407                 }
    408                 else if (g_strcasecmp( "id", child->name ) == 0)
    409                 {
    410                         txs->id = g_ascii_strtoull (child->text, NULL, 10);
    411                 }
    412                 else if (g_strcasecmp( "in_reply_to_status_id", child->name ) == 0)
    413                 {
    414                         txs->reply_to = g_ascii_strtoull (child->text, NULL, 10);
    415                 }
    416         }
    417        
     464        }
     465
    418466        /* If it's a truncated retweet, get the original because dots suck. */
    419         if (truncated && rt)
    420         {
     467        if (truncated && rt) {
    421468                struct twitter_xml_status *rtxs = g_new0(struct twitter_xml_status, 1);
    422                 if (twitter_xt_get_status(rt, rtxs) != XT_HANDLED)
    423                 {
     469                if (twitter_xt_get_status(rt, rtxs) != XT_HANDLED) {
    424470                        txs_free(rtxs);
    425471                        return XT_HANDLED;
    426472                }
    427                
     473
    428474                g_free(txs->text);
    429475                txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text);
    430476                txs_free(rtxs);
    431477        }
    432        
     478
    433479        return XT_HANDLED;
    434480}
     
    440486 *  - the next_cursor.
    441487 */
    442 static xt_status twitter_xt_get_status_list( struct im_connection *ic, struct xt_node *node, struct twitter_xml_list *txl )
     488static xt_status twitter_xt_get_status_list(struct im_connection *ic, struct xt_node *node,
     489                                            struct twitter_xml_list *txl)
    443490{
    444491        struct twitter_xml_status *txs;
     
    451498        // The root <statuses> node should hold the list of statuses <status>
    452499        // Walk over the nodes children.
    453         for( child = node->children ; child ; child = child->next )
    454         {
    455                 if ( g_strcasecmp( "status", child->name ) == 0)
    456                 {
     500        for (child = node->children; child; child = child->next) {
     501                if (g_strcasecmp("status", child->name) == 0) {
    457502                        txs = g_new0(struct twitter_xml_status, 1);
    458503                        twitter_xt_get_status(child, txs);
    459504                        // Put the item in the front of the list.
    460                         txl->list = g_slist_prepend (txl->list, txs);
    461                        
     505                        txl->list = g_slist_prepend(txl->list, txs);
     506
    462507                        if (txs->user && txs->user->screen_name &&
    463                             (bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name)))
    464                         {
     508                            (bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name))) {
    465509                                struct twitter_user_data *tud = bu->data;
    466                                
    467                                 if (txs->id > tud->last_id)
    468                                 {
     510
     511                                if (txs->id > tud->last_id) {
    469512                                        tud->last_id = txs->id;
    470513                                        tud->last_time = txs->created_at;
    471514                                }
    472515                        }
    473                 }
    474                 else if ( g_strcasecmp( "next_cursor", child->name ) == 0)
    475                 {
     516                } else if (g_strcasecmp("next_cursor", child->name) == 0) {
    476517                        twitter_xt_next_cursor(child, txl);
    477518                }
     
    490531        struct twitter_data *td = ic->proto_data;
    491532
    492         char* args[4];
     533        char *args[4];
    493534        args[0] = "cursor";
    494         args[1] = g_strdup_printf ("%lld", (long long) next_cursor);
     535        args[1] = g_strdup_printf("%lld", (long long) next_cursor);
    495536        if (td->home_timeline_id) {
    496537                args[2] = "since_id";
    497                 args[3] = g_strdup_printf ("%llu", (long long unsigned int) td->home_timeline_id);
    498         }
    499 
    500         twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, td->home_timeline_id ? 4 : 2);
     538                args[3] = g_strdup_printf("%llu", (long long unsigned int) td->home_timeline_id);
     539        }
     540
     541        twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args,
     542                     td->home_timeline_id ? 4 : 2);
    501543
    502544        g_free(args[1]);
     
    507549
    508550static char *twitter_msg_add_id(struct im_connection *ic,
    509     struct twitter_xml_status *txs, const char *prefix)
     551                                struct twitter_xml_status *txs, const char *prefix)
    510552{
    511553        struct twitter_data *td = ic->proto_data;
    512554        char *ret = NULL;
    513        
    514         if (!set_getbool(&ic->acc->set, "show_ids"))
    515         {
     555
     556        if (!set_getbool(&ic->acc->set, "show_ids")) {
    516557                if (*prefix)
    517558                        return g_strconcat(prefix, txs->text, NULL);
     
    519560                        return NULL;
    520561        }
    521        
     562
    522563        td->log[td->log_id].id = txs->id;
    523564        td->log[td->log_id].bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name);
    524         if (txs->reply_to)
    525         {
     565        if (txs->reply_to) {
    526566                int i;
    527                 for (i = 0; i < TWITTER_LOG_LENGTH; i ++)
    528                         if (td->log[i].id == txs->reply_to)
    529                         {
    530                                 ret = g_strdup_printf( "\002[\002%02d->%02d\002]\002 %s%s",
    531                                                        td->log_id, i, prefix, txs->text);
     567                for (i = 0; i < TWITTER_LOG_LENGTH; i++)
     568                        if (td->log[i].id == txs->reply_to) {
     569                                ret = g_strdup_printf("\002[\002%02d->%02d\002]\002 %s%s",
     570                                                      td->log_id, i, prefix, txs->text);
    532571                                break;
    533572                        }
    534573        }
    535574        if (ret == NULL)
    536                 ret = g_strdup_printf( "\002[\002%02d\002]\002 %s%s",
    537                                        td->log_id, prefix, txs->text);
     575                ret = g_strdup_printf("\002[\002%02d\002]\002 %s%s", td->log_id, prefix, txs->text);
    538576        td->log_id = (td->log_id + 1) % TWITTER_LOG_LENGTH;
    539        
     577
    540578        return ret;
    541579}
     
    547585        struct twitter_data *td = ic->proto_data;
    548586        GSList *l;
    549        
    550         td->home_timeline_gc = gc = imcb_chat_new( ic, "home/timeline" );
    551        
    552         name_hint = g_strdup_printf( "%s_%s", td->prefix, ic->acc->user );
    553         imcb_chat_name_hint( gc, name_hint );
    554         g_free( name_hint );
    555        
    556         for( l = ic->bee->users; l; l = l->next )
    557         {
     587
     588        td->home_timeline_gc = gc = imcb_chat_new(ic, "home/timeline");
     589
     590        name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user);
     591        imcb_chat_name_hint(gc, name_hint);
     592        g_free(name_hint);
     593
     594        for (l = ic->bee->users; l; l = l->next) {
    558595                bee_user_t *bu = l->data;
    559                 if( bu->ic == ic )
    560                         imcb_chat_add_buddy( td->home_timeline_gc, bu->handle );
     596                if (bu->ic == ic)
     597                        imcb_chat_add_buddy(td->home_timeline_gc, bu->handle);
    561598        }
    562599}
     
    565602 * Function that is called to see the statuses in a groupchat window.
    566603 */
    567 static void twitter_groupchat(struct im_connection *ic, GSList *list)
     604static void twitter_groupchat(struct im_connection *ic, GSList * list)
    568605{
    569606        struct twitter_data *td = ic->proto_data;
     
    575612        if (!td->home_timeline_gc)
    576613                twitter_groupchat_init(ic);
    577        
     614
    578615        gc = td->home_timeline_gc;
    579616        if (!gc->joined)
    580                 imcb_chat_add_buddy( gc, ic->acc->user );
    581 
    582         for ( l = list; l ; l = g_slist_next(l) )
    583         {
     617                imcb_chat_add_buddy(gc, ic->acc->user);
     618
     619        for (l = list; l; l = g_slist_next(l)) {
    584620                char *msg;
    585                
     621
    586622                status = l->data;
    587623                if (status->user == NULL || status->text == NULL)
     
    589625
    590626                twitter_add_buddy(ic, status->user->screen_name, status->user->name);
    591                
     627
    592628                strip_html(status->text);
    593629                msg = twitter_msg_add_id(ic, status, "");
    594                
     630
    595631                // Say it!
    596632                if (g_strcasecmp(td->user, status->user->screen_name) == 0)
     
    598634                else
    599635                        imcb_chat_msg(gc, status->user->screen_name,
    600                                       msg ? msg : status->text, 0, status->created_at );
    601                
     636                                      msg ? msg : status->text, 0, status->created_at);
     637
    602638                g_free(msg);
    603                
     639
    604640                // Update the home_timeline_id to hold the highest id, so that by the next request
    605641                // we won't pick up the updates already in the list.
     
    611647 * Function that is called to see statuses as private messages.
    612648 */
    613 static void twitter_private_message_chat(struct im_connection *ic, GSList *list)
     649static void twitter_private_message_chat(struct im_connection *ic, GSList * list)
    614650{
    615651        struct twitter_data *td = ic->proto_data;
     
    618654        char from[MAX_STRING];
    619655        gboolean mode_one;
    620        
    621         mode_one = g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "one" ) == 0;
    622 
    623         if( mode_one )
    624         {
    625                 g_snprintf( from, sizeof( from ) - 1, "%s_%s", td->prefix, ic->acc->user );
    626                 from[MAX_STRING-1] = '\0';
    627         }
    628        
    629         for ( l = list; l ; l = g_slist_next(l) )
    630         {
     656
     657        mode_one = g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "one") == 0;
     658
     659        if (mode_one) {
     660                g_snprintf(from, sizeof(from) - 1, "%s_%s", td->prefix, ic->acc->user);
     661                from[MAX_STRING - 1] = '\0';
     662        }
     663
     664        for (l = list; l; l = g_slist_next(l)) {
    631665                char *prefix = NULL, *text = NULL;
    632                
     666
    633667                status = l->data;
    634                
    635                 strip_html( status->text );
    636                 if( mode_one )
     668
     669                strip_html(status->text);
     670                if (mode_one)
    637671                        prefix = g_strdup_printf("\002<\002%s\002>\002 ",
    638                                                 status->user->screen_name);
     672                                                status->user->screen_name);
    639673                else
    640674                        twitter_add_buddy(ic, status->user->screen_name, status->user->name);
    641                
     675
    642676                text = twitter_msg_add_id(ic, status, prefix ? prefix : "");
    643                
    644                 imcb_buddy_msg( ic,
    645                                 mode_one ? from : status->user->screen_name,
    646                                 text ? text : status->text,
    647                                 0, status->created_at );
    648                
     677
     678                imcb_buddy_msg(ic,
     679                               mode_one ? from : status->user->screen_name,
     680                               text ? text : status->text, 0, status->created_at);
     681
    649682                // Update the home_timeline_id to hold the highest id, so that by the next request
    650683                // we won't pick up the updates already in the list.
    651                 td->home_timeline_id = MAX(td->home_timeline_id,  status->id);
    652                
    653                 g_free( text );
    654                 g_free( prefix );
     684                td->home_timeline_id = MAX(td->home_timeline_id, status->id);
     685
     686                g_free(text);
     687                g_free(prefix);
    655688        }
    656689}
     
    667700
    668701        // Check if the connection is still active.
    669         if( !g_slist_find( twitter_connections, ic ) )
    670                 return;
    671        
     702        if (!g_slist_find(twitter_connections, ic))
     703                return;
     704
    672705        td = ic->proto_data;
    673706
    674707        // Check if the HTTP request went well.
    675         if (req->status_code == 200)
    676         {
     708        if (req->status_code == 200) {
    677709                td->http_fails = 0;
    678710                if (!(ic->flags & OPT_LOGGED_IN))
    679711                        imcb_connected(ic);
    680         }
    681         else if (req->status_code == 401)
    682         {
    683                 imcb_error( ic, "Authentication failure" );
    684                 imc_logout( ic, FALSE );
    685                 return;
    686         }
    687         else
    688         {
     712        } else if (req->status_code == 401) {
     713                imcb_error(ic, "Authentication failure");
     714                imc_logout(ic, FALSE);
     715                return;
     716        } else {
    689717                // It didn't go well, output the error and return.
    690718                if (++td->http_fails >= 5)
    691                         imcb_error(ic, "Could not retrieve " TWITTER_HOME_TIMELINE_URL ": %s", twitter_parse_error(req));
    692                
     719                        imcb_error(ic, "Could not retrieve %s: %s",
     720                                   TWITTER_HOME_TIMELINE_URL, twitter_parse_error(req));
     721
    693722                return;
    694723        }
     
    698727
    699728        // Parse the data.
    700         parser = xt_new( NULL, txl );
    701         xt_feed( parser, req->reply_body, req->body_size );
     729        parser = xt_new(NULL, txl);
     730        xt_feed(parser, req->reply_body, req->body_size);
    702731        // The root <statuses> node should hold the list of statuses <status>
    703732        twitter_xt_get_status_list(ic, parser->root, txl);
    704         xt_free( parser );
     733        xt_free(parser);
    705734
    706735        // See if the user wants to see the messages in a groupchat window or as private messages.
    707         if (txl->list == NULL)
    708                 ;
     736        if (txl->list == NULL);
    709737        else if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
    710738                twitter_groupchat(ic, txl->list);
     
    712740                twitter_private_message_chat(ic, txl->list);
    713741
    714         // Free the structure. 
     742        // Free the structure. 
    715743        txl_free(txl);
    716744}
    717745
    718746/**
    719  * Callback for getting (twitter)friends...
    720  *
    721  * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has
    722  * hundreds of friends?" you wonder? You probably not, since you are reading the source of
    723  * BitlBee... Get a life and meet new people!
    724  */
    725 static void twitter_http_get_statuses_friends(struct http_request *req)
     747 * Callback to use after sending a POST request to twitter.
     748 * (Generic, used for a few kinds of queries.)
     749 */
     750static void twitter_http_post(struct http_request *req)
    726751{
    727752        struct im_connection *ic = req->data;
    728753        struct twitter_data *td;
    729         struct xt_parser *parser;
    730         struct twitter_xml_list *txl;
    731         GSList *l = NULL;
    732         struct twitter_xml_user *user;
    733754
    734755        // Check if the connection is still active.
    735         if( !g_slist_find( twitter_connections, ic ) )
    736                 return;
    737        
    738         td = ic->proto_data;
    739        
    740         // Check if the HTTP request went well.
    741         if (req->status_code == 401)
    742         {
    743                 imcb_error( ic, "Authentication failure" );
    744                 imc_logout( ic, FALSE );
    745                 return;
    746         } else if (req->status_code != 200) {
    747                 // It didn't go well, output the error and return.
    748                 imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s", twitter_parse_error(req));
    749                 imc_logout( ic, TRUE );
    750                 return;
    751         } else {
    752                 td->http_fails = 0;
    753         }
    754        
    755         if( !td->home_timeline_gc &&
    756             g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "chat" ) == 0 )
    757                 twitter_groupchat_init( ic );
    758 
    759         txl = g_new0(struct twitter_xml_list, 1);
    760         txl->list = NULL;
    761 
    762         // Parse the data.
    763         parser = xt_new( NULL, txl );
    764         xt_feed( parser, req->reply_body, req->body_size );
    765 
    766         // Get the user list from the parsed xml feed.
    767         twitter_xt_get_user_list(parser->root, txl);
    768         xt_free( parser );
    769 
    770         // Add the users as buddies.
    771         for ( l = txl->list; l ; l = g_slist_next(l) )
    772         {
    773                 user = l->data;
    774                 twitter_add_buddy(ic, user->screen_name, user->name);
    775         }
    776 
    777         // if the next_cursor is set to something bigger then 0 there are more friends to gather.
    778         if (txl->next_cursor > 0)
    779         {
    780                 twitter_get_statuses_friends(ic, txl->next_cursor);
    781         }
    782         else
    783         {
    784                 td->flags |= TWITTER_HAVE_FRIENDS;
    785                 twitter_login_finish(ic);
    786         }
    787        
    788         // Free the structure.
    789         txl_free(txl);
    790 }
    791 
    792 /**
    793  * Get the friends.
    794  */
    795 void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor)
    796 {
    797         char* args[2];
    798         args[0] = "cursor";
    799         args[1] = g_strdup_printf ("%lld", (long long) next_cursor);
    800 
    801         twitter_http(ic, TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, args, 2);
    802 
    803         g_free(args[1]);
    804 }
    805 
    806 /**
    807  * Callback to use after sending a post request to twitter.
    808  */
    809 static void twitter_http_post(struct http_request *req)
    810 {
    811         struct im_connection *ic = req->data;
    812         struct twitter_data *td;
    813 
    814         // Check if the connection is still active.
    815         if( !g_slist_find( twitter_connections, ic ) )
     756        if (!g_slist_find(twitter_connections, ic))
    816757                return;
    817758
    818759        td = ic->proto_data;
    819760        td->last_status_id = 0;
    820        
     761
    821762        // Check if the HTTP request went well.
    822763        if (req->status_code != 200) {
     
    825766                return;
    826767        }
    827        
    828         if (req->body_size > 0)
    829         {
     768
     769        if (req->body_size > 0) {
    830770                struct xt_parser *xp = NULL;
    831771                struct xt_node *node;
    832                
     772
    833773                xp = xt_new(NULL, NULL);
    834774                xt_feed(xp, req->reply_body, req->body_size);
    835                
     775
    836776                if ((node = xt_find_node(xp->root, "status")) &&
    837777                    (node = xt_find_node(node->children, "id")) && node->text)
    838                         td->last_status_id = g_ascii_strtoull( node->text, NULL, 10 );
    839                
     778                        td->last_status_id = g_ascii_strtoull(node->text, NULL, 10);
     779
    840780                xt_free(xp);
    841781        }
     
    844784/**
    845785 * Function to POST a new status to twitter.
    846  */ 
     786 */
    847787void twitter_post_status(struct im_connection *ic, char *msg, guint64 in_reply_to)
    848788{
    849         char* args[4] = {
     789        char *args[4] = {
    850790                "status", msg,
    851791                "in_reply_to_status_id",
     
    853793        };
    854794        twitter_http(ic, TWITTER_STATUS_UPDATE_URL, twitter_http_post, ic, 1,
    855                      args, in_reply_to ? 4 : 2);
     795                     args, in_reply_to ? 4 : 2);
    856796        g_free(args[3]);
    857797}
     
    863803void twitter_direct_messages_new(struct im_connection *ic, char *who, char *msg)
    864804{
    865         char* args[4];
     805        char *args[4];
    866806        args[0] = "screen_name";
    867807        args[1] = who;
     
    870810        // Use the same callback as for twitter_post_status, since it does basically the same.
    871811        twitter_http(ic, TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post, ic, 1, args, 4);
    872 //      g_free(args[1]);
    873 //      g_free(args[3]);
    874812}
    875813
    876814void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create)
    877815{
    878         char* args[2];
     816        char *args[2];
    879817        args[0] = "screen_name";
    880818        args[1] = who;
    881         twitter_http(ic, create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL, twitter_http_post, ic, 1, args, 2);
     819        twitter_http(ic, create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL,
     820                     twitter_http_post, ic, 1, args, 2);
    882821}
    883822
     
    885824{
    886825        char *url;
    887         url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_DESTROY_URL, (unsigned long long) id, ".xml");
     826        url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_DESTROY_URL,
     827                              (unsigned long long) id, ".xml");
    888828        twitter_http(ic, url, twitter_http_post, ic, 1, NULL, 0);
    889829        g_free(url);
     
    893833{
    894834        char *url;
    895         url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_RETWEET_URL, (unsigned long long) id, ".xml");
     835        url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_RETWEET_URL,
     836                              (unsigned long long) id, ".xml");
    896837        twitter_http(ic, url, twitter_http_post, ic, 1, NULL, 0);
    897838        g_free(url);
  • protocols/twitter/twitter_lib.h

    r17f6079 rc8b8c83  
    2929#include "twitter_http.h"
    3030
    31 #define TWITTER_API_URL "http://twitter.com"
    32 #define IDENTICA_API_URL "http://identi.ca/api"
     31#define TWITTER_API_URL "http://api.twitter.com/1"
     32#define IDENTICA_API_URL "https://identi.ca/api"
    3333
    3434/* Status URLs */
     
    4747
    4848/* Users URLs */
    49 #define TWITTER_SHOW_USERS_URL "/users/show.xml"
    50 #define TWITTER_SHOW_FRIENDS_URL "/statuses/friends.xml"
    51 #define TWITTER_SHOW_FOLLOWERS_URL "/statuses/followers.xml"
     49#define TWITTER_USERS_LOOKUP_URL "/users/lookup.xml"
    5250
    5351/* Direct messages URLs */
Note: See TracChangeset for help on using the changeset viewer.