Changeset 5983eca
- Timestamp:
- 2011-06-11T11:28:01Z (13 years ago)
- Branches:
- master
- Children:
- 5f74987
- Parents:
- 27ad50b
- Location:
- protocols/twitter
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/twitter/twitter.c
r27ad50b r5983eca 37 37 imcb_log( ic, fmt ); \ 38 38 } while( 0 ); 39 39 40 40 GSList *twitter_connections = NULL; 41 41 … … 46 46 { 47 47 struct im_connection *ic = data; 48 48 49 49 // Check if we are still logged in... 50 if (!g_slist_find( twitter_connections, ic))50 if (!g_slist_find(twitter_connections, ic)) 51 51 return 0; 52 52 … … 58 58 } 59 59 60 static void twitter_main_loop_start( struct im_connection *ic)61 { 62 struct twitter_data *td = ic->proto_data; 63 64 imcb_log( ic, "Getting initial statuses");60 static void twitter_main_loop_start(struct im_connection *ic) 61 { 62 struct twitter_data *td = ic->proto_data; 63 64 imcb_log(ic, "Getting initial statuses"); 65 65 66 66 // Run this once. After this queue the main loop function. … … 72 72 } 73 73 74 static void twitter_oauth_start( struct im_connection *ic ); 75 76 void twitter_login_finish( struct im_connection *ic ) 77 { 78 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 { 74 static void twitter_oauth_start(struct im_connection *ic); 75 76 void twitter_login_finish(struct im_connection *ic) 77 { 78 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 imcb_log(ic, "Getting contact list"); 85 twitter_get_statuses_friends(ic, -1); 86 } else 87 twitter_main_loop_start(ic); 88 } 89 90 static const struct oauth_service twitter_oauth = { 94 91 "http://api.twitter.com/oauth/request_token", 95 92 "http://api.twitter.com/oauth/access_token", … … 99 96 }; 100 97 101 static const struct oauth_service identica_oauth = 102 { 98 static const struct oauth_service identica_oauth = { 103 99 "http://identi.ca/api/oauth/request_token", 104 100 "http://identi.ca/api/oauth/access_token", … … 108 104 }; 109 105 110 static gboolean twitter_oauth_callback( struct oauth_info *info);111 112 static const struct oauth_service *get_oauth_service( struct im_connection *ic)113 { 114 struct twitter_data *td = ic->proto_data; 115 116 if ( strstr( td->url_host, "identi.ca" ))106 static gboolean twitter_oauth_callback(struct oauth_info *info); 107 108 static const struct oauth_service *get_oauth_service(struct im_connection *ic) 109 { 110 struct twitter_data *td = ic->proto_data; 111 112 if (strstr(td->url_host, "identi.ca")) 117 113 return &identica_oauth; 118 114 else 119 115 return &twitter_oauth; 120 116 121 117 /* Could add more services, or allow configuring your own base URL + 122 118 API keys. */ 123 119 } 124 120 125 static void twitter_oauth_start( struct im_connection *ic)126 { 127 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 121 static void twitter_oauth_start(struct im_connection *ic) 122 { 123 struct twitter_data *td = ic->proto_data; 124 125 imcb_log(ic, "Requesting OAuth request token"); 126 127 td->oauth_info = oauth_request_token(get_oauth_service(ic), twitter_oauth_callback, ic); 128 133 129 /* We need help from the user to complete OAuth login, so don't time 134 130 out on this login. */ … … 136 132 } 137 133 138 static gboolean twitter_oauth_callback( struct oauth_info *info)134 static gboolean twitter_oauth_callback(struct oauth_info *info) 139 135 { 140 136 struct im_connection *ic = info->data; 141 137 struct twitter_data *td; 142 143 if ( !g_slist_find( twitter_connections, ic ))138 139 if (!g_slist_find(twitter_connections, ic)) 144 140 return FALSE; 145 141 146 142 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", twitter_parse_error( info->http ) ); 154 imc_logout( ic, TRUE ); 143 if (info->stage == OAUTH_REQUEST_TOKEN) { 144 char name[strlen(ic->acc->user) + 9], *msg; 145 146 if (info->request_token == NULL) { 147 imcb_error(ic, "OAuth error: %s", twitter_parse_error(info->http)); 148 imc_logout(ic, TRUE); 155 149 return FALSE; 156 150 } 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", twitter_parse_error( info->http ) ); 170 imc_logout( ic, TRUE ); 151 152 sprintf(name, "%s_%s", td->prefix, ic->acc->user); 153 msg = g_strdup_printf("To finish OAuth authentication, please visit " 154 "%s and respond with the resulting PIN code.", 155 info->auth_url); 156 imcb_buddy_msg(ic, name, msg, 0, 0); 157 g_free(msg); 158 } else if (info->stage == OAUTH_ACCESS_TOKEN) { 159 if (info->token == NULL || info->token_secret == NULL) { 160 imcb_error(ic, "OAuth error: %s", twitter_parse_error(info->http)); 161 imc_logout(ic, TRUE); 171 162 return FALSE; 172 } 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 ); 163 } else { 164 const char *sn = oauth_params_get(&info->params, "screen_name"); 165 166 if (sn != NULL && ic->acc->prpl->handle_cmp(sn, ic->acc->user) != 0) { 167 imcb_log(ic, "Warning: You logged in via OAuth as %s " 168 "instead of %s.", sn, ic->acc->user); 181 169 } 182 170 } 183 171 184 172 /* IM mods didn't do this so far and it's ugly but I should 185 173 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 174 g_free(ic->acc->pass); 175 ic->acc->pass = oauth_to_string(info); 176 177 twitter_login_finish(ic); 178 } 179 192 180 return TRUE; 193 181 } 194 182 195 183 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 ) 184 static char *set_eval_mode(set_t * set, char *value) 185 { 186 if (g_strcasecmp(value, "one") == 0 || 187 g_strcasecmp(value, "many") == 0 || g_strcasecmp(value, "chat") == 0) 201 188 return value; 202 189 else … … 204 191 } 205 192 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)193 static gboolean twitter_length_check(struct im_connection *ic, gchar * msg) 194 { 195 int max = set_getint(&ic->acc->set, "message_length"), len; 196 197 if (max == 0 || (len = g_utf8_strlen(msg, -1)) <= max) 211 198 return TRUE; 212 213 imcb_error( ic, "Maximum message length exceeded: %d > %d", len, max);214 199 200 imcb_error(ic, "Maximum message length exceeded: %d > %d", len, max); 201 215 202 return FALSE; 216 203 } 217 204 218 static void twitter_init( account_t *acc)205 static void twitter_init(account_t * acc) 219 206 { 220 207 set_t *s; 221 208 char *def_url; 222 209 char *def_oauth; 223 224 if( strcmp( acc->prpl->name, "twitter" ) == 0 ) 225 { 210 211 if (strcmp(acc->prpl->name, "twitter") == 0) { 226 212 def_url = TWITTER_API_URL; 227 213 def_oauth = "true"; 228 } 229 else /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */ 230 { 214 } else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */ 215 231 216 def_url = IDENTICA_API_URL; 232 217 def_oauth = "false"; 233 218 } 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);219 220 s = set_add(&acc->set, "auto_reply_timeout", "10800", set_eval_int, acc); 221 222 s = set_add(&acc->set, "base_url", def_url, NULL, acc); 238 223 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);224 225 s = set_add(&acc->set, "commands", "true", set_eval_bool, acc); 226 227 s = set_add(&acc->set, "message_length", "140", set_eval_int, acc); 228 229 s = set_add(&acc->set, "mode", "chat", set_eval_mode, acc); 245 230 s->flags |= ACC_SET_OFFLINE_ONLY; 246 247 s = set_add( &acc->set, "show_ids", "false", set_eval_bool, acc);231 232 s = set_add(&acc->set, "show_ids", "false", set_eval_bool, acc); 248 233 s->flags |= ACC_SET_OFFLINE_ONLY; 249 250 s = set_add( &acc->set, "oauth", def_oauth, set_eval_bool, acc);234 235 s = set_add(&acc->set, "oauth", def_oauth, set_eval_bool, acc); 251 236 } 252 237 … … 255 240 * only save the user and pass to the twitter_data object. 256 241 */ 257 static void twitter_login( account_t *acc)258 { 259 struct im_connection *ic = imcb_new( acc);242 static void twitter_login(account_t * acc) 243 { 244 struct im_connection *ic = imcb_new(acc); 260 245 struct twitter_data *td; 261 char name[strlen(acc->user) +9];246 char name[strlen(acc->user) + 9]; 262 247 url_t url; 263 248 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 ); 249 if (!url_set(&url, set_getstr(&ic->acc->set, "base_url")) || 250 (url.proto != PROTO_HTTP && url.proto != PROTO_HTTPS)) { 251 imcb_error(ic, "Incorrect API base URL: %s", set_getstr(&ic->acc->set, "base_url")); 252 imc_logout(ic, FALSE); 269 253 return; 270 254 } 271 272 twitter_connections = g_slist_append( twitter_connections, ic);273 td = g_new0( struct twitter_data, 1);255 256 twitter_connections = g_slist_append(twitter_connections, ic); 257 td = g_new0(struct twitter_data, 1); 274 258 ic->proto_data = td; 275 259 276 260 td->url_ssl = url.proto == PROTO_HTTPS; 277 261 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);262 td->url_host = g_strdup(url.host); 263 if (strcmp(url.file, "/") != 0) 264 td->url_path = g_strdup(url.file); 281 265 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);266 td->url_path = g_strdup(""); 267 if (g_str_has_suffix(url.host, ".com")) 268 td->prefix = g_strndup(url.host, strlen(url.host) - 4); 285 269 else 286 td->prefix = g_strdup( url.host);287 270 td->prefix = g_strdup(url.host); 271 288 272 td->flags |= TWITTER_HAVE_FRIENDS; 289 273 td->user = acc->user; 290 if ( strstr( acc->pass, "oauth_token=" ))291 td->oauth_info = oauth_from_string( acc->pass, get_oauth_service( ic ));292 293 sprintf( name, "%s_%s", td->prefix, acc->user);294 imcb_add_buddy( ic, name, NULL);295 imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL);296 297 if ( set_getbool( &acc->set, "show_ids" ))298 td->log = g_new0( struct twitter_log_data, TWITTER_LOG_LENGTH);299 300 imcb_log( ic, "Connecting");301 302 twitter_login_finish( ic);274 if (strstr(acc->pass, "oauth_token=")) 275 td->oauth_info = oauth_from_string(acc->pass, get_oauth_service(ic)); 276 277 sprintf(name, "%s_%s", td->prefix, acc->user); 278 imcb_add_buddy(ic, name, NULL); 279 imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL); 280 281 if (set_getbool(&acc->set, "show_ids")) 282 td->log = g_new0(struct twitter_log_data, TWITTER_LOG_LENGTH); 283 284 imcb_log(ic, "Connecting"); 285 286 twitter_login_finish(ic); 303 287 } 304 288 … … 306 290 * Logout method. Just free the twitter_data. 307 291 */ 308 static void twitter_logout( struct im_connection *ic)309 { 310 struct twitter_data *td = ic->proto_data; 311 292 static void twitter_logout(struct im_connection *ic) 293 { 294 struct twitter_data *td = ic->proto_data; 295 312 296 // Set the status to logged out. 313 ic->flags &= ~ 297 ic->flags &= ~OPT_LOGGED_IN; 314 298 315 299 // Remove the main_loop function from the function queue. 316 300 b_event_remove(td->main_loop_id); 317 301 318 if (td->home_timeline_gc)302 if (td->home_timeline_gc) 319 303 imcb_chat_free(td->home_timeline_gc); 320 304 321 if( td ) 322 { 323 oauth_info_free( td->oauth_info ); 324 g_free( td->prefix ); 325 g_free( td->url_host ); 326 g_free( td->url_path ); 327 g_free( td->pass ); 328 g_free( td->log ); 329 g_free( td ); 330 } 331 332 twitter_connections = g_slist_remove( twitter_connections, ic ); 333 } 334 335 static void twitter_handle_command( struct im_connection *ic, char *message ); 305 if (td) { 306 oauth_info_free(td->oauth_info); 307 g_free(td->prefix); 308 g_free(td->url_host); 309 g_free(td->url_path); 310 g_free(td->pass); 311 g_free(td->log); 312 g_free(td); 313 } 314 315 twitter_connections = g_slist_remove(twitter_connections, ic); 316 } 317 318 static void twitter_handle_command(struct im_connection *ic, char *message); 336 319 337 320 /** 338 321 * 339 322 */ 340 static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message, int away)341 { 342 struct twitter_data *td = ic->proto_data; 343 int plen = strlen( td->prefix);344 323 static int twitter_buddy_msg(struct im_connection *ic, char *who, char *message, int away) 324 { 325 struct twitter_data *td = ic->proto_data; 326 int plen = strlen(td->prefix); 327 345 328 if (g_strncasecmp(who, td->prefix, plen) == 0 && who[plen] == '_' && 346 g_strcasecmp(who + plen + 1, ic->acc->user) == 0) 347 { 348 if( set_getbool( &ic->acc->set, "oauth" ) && 349 td->oauth_info && td->oauth_info->token == NULL ) 350 { 351 char pin[strlen(message)+1], *s; 352 353 strcpy( pin, message ); 354 for( s = pin + sizeof( pin ) - 2; s > pin && isspace( *s ); s -- ) 329 g_strcasecmp(who + plen + 1, ic->acc->user) == 0) { 330 if (set_getbool(&ic->acc->set, "oauth") && 331 td->oauth_info && td->oauth_info->token == NULL) { 332 char pin[strlen(message) + 1], *s; 333 334 strcpy(pin, message); 335 for (s = pin + sizeof(pin) - 2; s > pin && isspace(*s); s--) 355 336 *s = '\0'; 356 for( s = pin; *s && isspace( *s ); s ++ ) {} 357 358 if( !oauth_access_token( s, td->oauth_info ) ) 359 { 360 imcb_error( ic, "OAuth error: %s", "Failed to send access token request" ); 361 imc_logout( ic, TRUE ); 337 for (s = pin; *s && isspace(*s); s++) { 338 } 339 340 if (!oauth_access_token(s, td->oauth_info)) { 341 imcb_error(ic, "OAuth error: %s", 342 "Failed to send access token request"); 343 imc_logout(ic, TRUE); 362 344 return FALSE; 363 345 } 364 } 365 else 346 } else 366 347 twitter_handle_command(ic, message); 367 } 368 else 369 { 348 } else { 370 349 twitter_direct_messages_new(ic, who, message); 371 350 } 372 return ( 0);351 return (0); 373 352 } 374 353 … … 376 355 * 377 356 */ 378 static void twitter_set_my_name( struct im_connection *ic, char *info)379 { 380 } 381 382 static void twitter_get_info(struct im_connection *ic, char *who) 383 { 384 } 385 386 static void twitter_add_buddy( struct im_connection *ic, char *who, char *group)357 static void twitter_set_my_name(struct im_connection *ic, char *info) 358 { 359 } 360 361 static void twitter_get_info(struct im_connection *ic, char *who) 362 { 363 } 364 365 static void twitter_add_buddy(struct im_connection *ic, char *who, char *group) 387 366 { 388 367 twitter_friendships_create_destroy(ic, who, 1); 389 368 } 390 369 391 static void twitter_remove_buddy( struct im_connection *ic, char *who, char *group)370 static void twitter_remove_buddy(struct im_connection *ic, char *who, char *group) 392 371 { 393 372 twitter_friendships_create_destroy(ic, who, 0); 394 373 } 395 374 396 static void twitter_chat_msg( struct groupchat *c, char *message, int flags)397 { 398 if ( c && message)399 twitter_handle_command( c->ic, message);400 } 401 402 static void twitter_chat_invite( struct groupchat *c, char *who, char *message)403 { 404 } 405 406 static void twitter_chat_leave( struct groupchat *c)375 static void twitter_chat_msg(struct groupchat *c, char *message, int flags) 376 { 377 if (c && message) 378 twitter_handle_command(c->ic, message); 379 } 380 381 static void twitter_chat_invite(struct groupchat *c, char *who, char *message) 382 { 383 } 384 385 static void twitter_chat_leave(struct groupchat *c) 407 386 { 408 387 struct twitter_data *td = c->ic->proto_data; 409 410 if ( c != td->home_timeline_gc)411 return; 412 388 389 if (c != td->home_timeline_gc) 390 return; /* WTF? */ 391 413 392 /* If the user leaves the channel: Fine. Rejoin him/her once new 414 393 tweets come in. */ … … 417 396 } 418 397 419 static void twitter_keepalive( struct im_connection *ic)420 { 421 } 422 423 static void twitter_add_permit( struct im_connection *ic, char *who)424 { 425 } 426 427 static void twitter_rem_permit( struct im_connection *ic, char *who)428 { 429 } 430 431 static void twitter_add_deny( struct im_connection *ic, char *who)432 { 433 } 434 435 static void twitter_rem_deny( struct im_connection *ic, char *who)398 static void twitter_keepalive(struct im_connection *ic) 399 { 400 } 401 402 static void twitter_add_permit(struct im_connection *ic, char *who) 403 { 404 } 405 406 static void twitter_rem_permit(struct im_connection *ic, char *who) 407 { 408 } 409 410 static void twitter_add_deny(struct im_connection *ic, char *who) 411 { 412 } 413 414 static void twitter_rem_deny(struct im_connection *ic, char *who) 436 415 { 437 416 } … … 439 418 //static char *twitter_set_display_name( set_t *set, char *value ) 440 419 //{ 441 // 420 // return value; 442 421 //} 443 422 444 static void twitter_buddy_data_add( struct bee_user *bu)445 { 446 bu->data = g_new0( struct twitter_user_data, 1);447 } 448 449 static void twitter_buddy_data_free( struct bee_user *bu)450 { 451 g_free( bu->data);452 } 453 454 static void twitter_handle_command( struct im_connection *ic, char *message)423 static void twitter_buddy_data_add(struct bee_user *bu) 424 { 425 bu->data = g_new0(struct twitter_user_data, 1); 426 } 427 428 static void twitter_buddy_data_free(struct bee_user *bu) 429 { 430 g_free(bu->data); 431 } 432 433 static void twitter_handle_command(struct im_connection *ic, char *message) 455 434 { 456 435 struct twitter_data *td = ic->proto_data; 457 436 char *cmds, **cmd, *new = NULL; 458 437 guint64 in_reply_to = 0; 459 460 cmds = g_strdup( message ); 461 cmd = split_command_parts( cmds ); 462 463 if( cmd[0] == NULL ) 464 { 465 g_free( cmds ); 438 439 cmds = g_strdup(message); 440 cmd = split_command_parts(cmds); 441 442 if (cmd[0] == NULL) { 443 g_free(cmds); 466 444 return; 467 } 468 else if( !set_getbool( &ic->acc->set, "commands" ) ) 469 { 445 } else if (!set_getbool(&ic->acc->set, "commands")) { 470 446 /* Not supporting commands. */ 471 } 472 else if( g_strcasecmp( cmd[0], "undo" ) == 0 ) 473 { 447 } else if (g_strcasecmp(cmd[0], "undo") == 0) { 474 448 guint64 id; 475 476 if ( cmd[1])477 id = g_ascii_strtoull( cmd[1], NULL, 10);449 450 if (cmd[1]) 451 id = g_ascii_strtoull(cmd[1], NULL, 10); 478 452 else 479 453 id = td->last_status_id; 480 454 481 455 /* TODO: User feedback. */ 482 if ( id)483 twitter_status_destroy( ic, id);456 if (id) 457 twitter_status_destroy(ic, id); 484 458 else 485 twitter_msg( ic, "Could not undo last action");486 487 g_free( cmds);459 twitter_msg(ic, "Could not undo last action"); 460 461 g_free(cmds); 488 462 return; 489 } 490 else if( g_strcasecmp( cmd[0], "follow" ) == 0 && cmd[1] ) 491 { 492 twitter_add_buddy( ic, cmd[1], NULL ); 493 g_free( cmds ); 463 } else if (g_strcasecmp(cmd[0], "follow") == 0 && cmd[1]) { 464 twitter_add_buddy(ic, cmd[1], NULL); 465 g_free(cmds); 494 466 return; 495 } 496 else if( g_strcasecmp( cmd[0], "unfollow" ) == 0 && cmd[1] ) 497 { 498 twitter_remove_buddy( ic, cmd[1], NULL ); 499 g_free( cmds ); 467 } else if (g_strcasecmp(cmd[0], "unfollow") == 0 && cmd[1]) { 468 twitter_remove_buddy(ic, cmd[1], NULL); 469 g_free(cmds); 500 470 return; 501 } 502 else if( g_strcasecmp( cmd[0], "rt" ) == 0 && cmd[1] ) 503 { 471 } else if (g_strcasecmp(cmd[0], "rt") == 0 && cmd[1]) { 504 472 struct twitter_user_data *tud; 505 473 bee_user_t *bu; 506 474 guint64 id; 507 508 if ( ( bu = bee_user_by_handle( ic->bee, ic, cmd[1] )) &&509 ( tud = bu->data ) && tud->last_id)475 476 if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) && 477 (tud = bu->data) && tud->last_id) 510 478 id = tud->last_id; 479 else { 480 id = g_ascii_strtoull(cmd[1], NULL, 10); 481 if (id < TWITTER_LOG_LENGTH && td->log) 482 id = td->log[id].id; 483 } 484 485 td->last_status_id = 0; 486 if (id) 487 twitter_status_retweet(ic, id); 511 488 else 512 { 513 id = g_ascii_strtoull( cmd[1], NULL, 10 ); 514 if( id < TWITTER_LOG_LENGTH && td->log ) 515 id = td->log[id].id; 516 } 517 518 td->last_status_id = 0; 519 if( id ) 520 twitter_status_retweet( ic, id ); 521 else 522 twitter_msg( ic, "User `%s' does not exist or didn't " 523 "post any statuses recently", cmd[1] ); 524 525 g_free( cmds ); 489 twitter_msg(ic, "User `%s' does not exist or didn't " 490 "post any statuses recently", cmd[1]); 491 492 g_free(cmds); 526 493 return; 527 } 528 else if( g_strcasecmp( cmd[0], "reply" ) == 0 && cmd[1] && cmd[2] ) 529 { 494 } else if (g_strcasecmp(cmd[0], "reply") == 0 && cmd[1] && cmd[2]) { 530 495 struct twitter_user_data *tud; 531 496 bee_user_t *bu = NULL; 532 497 guint64 id = 0; 533 534 if( ( bu = bee_user_by_handle( ic->bee, ic, cmd[1] ) ) && 535 ( tud = bu->data ) && tud->last_id ) 536 { 498 499 if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) && 500 (tud = bu->data) && tud->last_id) { 537 501 id = tud->last_id; 538 } 539 else if( ( id = g_ascii_strtoull( cmd[1], NULL, 10 ) ) && 540 ( id < TWITTER_LOG_LENGTH ) && td->log ) 541 { 502 } else if ((id = g_ascii_strtoull(cmd[1], NULL, 10)) && 503 (id < TWITTER_LOG_LENGTH) && td->log) { 542 504 bu = td->log[id].bu; 543 if ( g_slist_find( ic->bee->users, bu ))505 if (g_slist_find(ic->bee->users, bu)) 544 506 id = td->log[id].id; 545 507 else 546 508 bu = NULL; 547 509 } 548 if( !id || !bu ) 549 { 550 twitter_msg( ic, "User `%s' does not exist or didn't " 551 "post any statuses recently", cmd[1] ); 510 if (!id || !bu) { 511 twitter_msg(ic, "User `%s' does not exist or didn't " 512 "post any statuses recently", cmd[1]); 552 513 return; 553 514 } 554 message = new = g_strdup_printf( "@%s %s", bu->handle, 555 message + ( cmd[2] - cmd[0] ) ); 515 message = new = g_strdup_printf("@%s %s", bu->handle, message + (cmd[2] - cmd[0])); 556 516 in_reply_to = id; 557 } 558 else if( g_strcasecmp( cmd[0], "post" ) == 0 ) 559 { 517 } else if (g_strcasecmp(cmd[0], "post") == 0) { 560 518 message += 5; 561 519 } 562 520 563 521 { 564 522 char *s; 565 523 bee_user_t *bu; 566 567 if( !twitter_length_check( ic, message ) ) 568 { 569 g_free( new ); 570 g_free( cmds ); 571 return; 572 } 573 574 s = cmd[0] + strlen( cmd[0] ) - 1; 575 if( !new && s > cmd[0] && ( *s == ':' || *s == ',' ) ) 576 { 524 525 if (!twitter_length_check(ic, message)) { 526 g_free(new); 527 g_free(cmds); 528 return; 529 } 530 531 s = cmd[0] + strlen(cmd[0]) - 1; 532 if (!new && s > cmd[0] && (*s == ':' || *s == ',')) { 577 533 *s = '\0'; 578 579 if( ( bu = bee_user_by_handle( ic->bee, ic, cmd[0] ) ) ) 580 { 534 535 if ((bu = bee_user_by_handle(ic->bee, ic, cmd[0]))) { 581 536 struct twitter_user_data *tud = bu->data; 582 583 new = g_strdup_printf( 584 message + ( s - cmd[0] ) + 2);537 538 new = g_strdup_printf("@%s %s", bu->handle, 539 message + (s - cmd[0]) + 2); 585 540 message = new; 586 587 if ( time( NULL) < tud->last_time +588 set_getint( &ic->acc->set, "auto_reply_timeout" ))541 542 if (time(NULL) < tud->last_time + 543 set_getint(&ic->acc->set, "auto_reply_timeout")) 589 544 in_reply_to = tud->last_id; 590 545 } 591 546 } 592 547 593 548 /* If the user runs undo between this request and its response 594 549 this would delete the second-last Tweet. Prevent that. */ 595 550 td->last_status_id = 0; 596 twitter_post_status( ic, message, in_reply_to);597 g_free( new);598 } 599 g_free( cmds);551 twitter_post_status(ic, message, in_reply_to); 552 g_free(new); 553 } 554 g_free(cmds); 600 555 } 601 556 … … 603 558 { 604 559 struct prpl *ret = g_new0(struct prpl, 1); 605 560 606 561 ret->options = OPT_NOOTR; 607 562 ret->name = "twitter"; … … 625 580 ret->buddy_data_free = twitter_buddy_data_free; 626 581 ret->handle_cmp = g_strcasecmp; 627 582 628 583 register_protocol(ret); 629 584 -
protocols/twitter/twitter_http.c
r27ad50b r5983eca 27 27 * BitlBee. * 28 28 * * 29 ****************************************************************************/ 29 ****************************************************************************/ 30 30 31 31 #include "twitter.h" … … 41 41 42 42 43 static char *twitter_url_append(char *url, char *key, char *value);43 static char *twitter_url_append(char *url, char *key, char *value); 44 44 45 45 /** … … 47 47 * This is actually pretty generic function... Perhaps it should move to the lib/http_client.c 48 48 */ 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) 49 void *twitter_http(struct im_connection *ic, char *url_string, http_input_function func, 50 gpointer data, int is_post, char **arguments, int arguments_len) 50 51 { 51 52 struct twitter_data *td = ic->proto_data; … … 58 59 59 60 // Construct the url arguments. 60 if (arguments_len != 0) 61 { 61 if (arguments_len != 0) { 62 62 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]); 66 65 g_free(url_arguments); 67 66 url_arguments = tmp; 68 67 } 69 68 } 70 71 69 // Make the request. 72 70 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); 79 76 80 77 // If a pass and user are given we append them to the request. 81 if (td->oauth_info) 82 { 78 if (td->oauth_info) { 83 79 char *full_header; 84 80 char *full_url; 85 86 full_url = g_strconcat(set_getstr(&ic->acc->set, "base_url" 81 82 full_url = g_strconcat(set_getstr(&ic->acc->set, "base_url"), url_string, NULL); 87 83 full_header = oauth_http_header(td->oauth_info, is_post ? "POST" : "GET", 88 89 84 full_url, url_arguments); 85 90 86 g_string_append_printf(request, "Authorization: %s\r\n", full_header); 91 87 g_free(full_header); 92 88 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)]; 97 91 char *userpass_base64; 98 92 99 93 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)); 101 95 g_string_append_printf(request, "Authorization: Basic %s\r\n", userpass_base64); 102 g_free( userpass_base64);96 g_free(userpass_base64); 103 97 } 104 98 105 99 // Do POST stuff.. 106 if (is_post) 107 { 100 if (is_post) { 108 101 // Append the Content-Type and url-encoded arguments. 109 102 g_string_append_printf(request, 110 111 112 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); 113 106 } else { 114 107 // Append an extra \r\n to end the request... … … 118 111 ret = http_dorequest(td->url_host, td->url_port, td->url_ssl, request->str, func, data); 119 112 120 g_free( url_arguments);121 g_string_free( request, TRUE);113 g_free(url_arguments); 114 g_string_free(request, TRUE); 122 115 return ret; 123 116 } 124 117 125 static char *twitter_url_append(char *url, char *key, char *value)118 static char *twitter_url_append(char *url, char *key, char *value) 126 119 { 127 120 char *key_encoded = g_strndup(key, 3 * strlen(key)); -
protocols/twitter/twitter_lib.c
r27ad50b r5983eca 104 104 if (txl == NULL) 105 105 return; 106 for ( l = txl->list; l ; l = g_slist_next(l))106 for (l = txl->list; l; l = g_slist_next(l)) 107 107 if (txl->type == TXL_STATUS) 108 txs_free((struct twitter_xml_status *) l->data);108 txs_free((struct twitter_xml_status *) l->data); 109 109 else if (txl->type == TXL_ID) 110 110 g_free(l->data); … … 121 121 122 122 // Check if the buddy is allready in the buddy list. 123 if (!bee_user_by_handle( ic->bee, ic, name )) 124 { 123 if (!bee_user_by_handle(ic->bee, ic, name)) { 125 124 char *mode = set_getstr(&ic->acc->set, "mode"); 126 125 127 126 // 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 { 127 imcb_add_buddy(ic, name, NULL); 128 imcb_rename_buddy(ic, name, fullname); 129 if (g_strcasecmp(mode, "chat") == 0) { 132 130 /* Necessary so that nicks always get translated to the 133 131 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 ); 132 imcb_buddy_nick_hint(ic, name, name); 133 imcb_chat_add_buddy(td->home_timeline_gc, name); 134 } else if (g_strcasecmp(mode, "many") == 0) 135 imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL); 139 136 } 140 137 } … … 147 144 struct xt_parser *xp = NULL; 148 145 struct xt_node *node; 149 146 150 147 g_free(ret); 151 148 ret = NULL; 152 153 if (req->body_size > 0) 154 { 149 150 if (req->body_size > 0) { 155 151 xp = xt_new(NULL, NULL); 156 152 xt_feed(xp, req->reply_body, req->body_size); 157 153 158 154 if ((node = xt_find_node(xp->root, "hash")) && 159 (node = xt_find_node(node->children, "error")) && 160 node->text_len > 0) 161 { 155 (node = xt_find_node(node->children, "error")) && node->text_len > 0) { 162 156 ret = g_strdup_printf("%s (%s)", req->status_string, node->text); 163 157 } 164 158 165 159 xt_free(xp); 166 160 } 167 161 168 162 return ret ? ret : req->status_string; 169 163 } … … 176 170 void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor) 177 171 { 178 // Primitive, but hey! It works... 179 char *args[2];172 // Primitive, but hey! It works... 173 char *args[2]; 180 174 args[0] = "cursor"; 181 args[1] = g_strdup_printf 175 args[1] = g_strdup_printf("%lld", (long long) next_cursor); 182 176 twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2); 183 177 … … 188 182 * Function to help fill a list. 189 183 */ 190 static xt_status twitter_xt_next_cursor( struct xt_node *node, struct twitter_xml_list *txl)184 static xt_status twitter_xt_next_cursor(struct xt_node *node, struct twitter_xml_list *txl) 191 185 { 192 186 char *end = NULL; 193 194 if ( node->text)195 txl->next_cursor = g_ascii_strtoll( node->text, &end, 10);196 if ( end == NULL)187 188 if (node->text) 189 txl->next_cursor = g_ascii_strtoll(node->text, &end, 10); 190 if (end == NULL) 197 191 txl->next_cursor = -1; 198 192 … … 203 197 * Fill a list of ids. 204 198 */ 205 static xt_status twitter_xt_get_friends_id_list( struct xt_node *node, struct twitter_xml_list *txl)199 static xt_status twitter_xt_get_friends_id_list(struct xt_node *node, struct twitter_xml_list *txl) 206 200 { 207 201 struct xt_node *child; 208 202 209 203 // Set the list type. 210 204 txl->type = TXL_ID; … … 212 206 // The root <statuses> node should hold the list of statuses <status> 213 207 // Walk over the nodes children. 214 for( child = node->children ; child ; child = child->next ) 215 { 216 if ( g_strcasecmp( "id", child->name ) == 0) 217 { 208 for (child = node->children; child; child = child->next) { 209 if (g_strcasecmp("id", child->name) == 0) { 218 210 // Add the item to the list. 219 txl->list = g_slist_append (txl->list, g_memdup( child->text, child->text_len + 1 )); 220 } 221 else if ( g_strcasecmp( "next_cursor", child->name ) == 0) 222 { 211 txl->list = 212 g_slist_append(txl->list, g_memdup(child->text, child->text_len + 1)); 213 } else if (g_strcasecmp("next_cursor", child->name) == 0) { 223 214 twitter_xt_next_cursor(child, txl); 224 215 } … … 241 232 242 233 // Check if the connection is still active. 243 if ( !g_slist_find( twitter_connections, ic ))244 return; 245 234 if (!g_slist_find(twitter_connections, ic)) 235 return; 236 246 237 td = ic->proto_data; 247 238 … … 251 242 if (++td->http_fails >= 5) 252 243 imcb_error(ic, "Could not retrieve friends: %s", twitter_parse_error(req)); 253 244 254 245 return; 255 246 } else { … … 260 251 261 252 // Parse the data. 262 parser = xt_new( NULL, txl);263 xt_feed( parser, req->reply_body, req->body_size);253 parser = xt_new(NULL, txl); 254 xt_feed(parser, req->reply_body, req->body_size); 264 255 twitter_xt_get_friends_id_list(parser->root, txl); 265 xt_free( parser);256 xt_free(parser); 266 257 267 258 if (txl->next_cursor) … … 277 268 * - the screen_name. 278 269 */ 279 static xt_status twitter_xt_get_user( struct xt_node *node, struct twitter_xml_user *txu)270 static xt_status twitter_xt_get_user(struct xt_node *node, struct twitter_xml_user *txu) 280 271 { 281 272 struct xt_node *child; 282 273 283 274 // Walk over the nodes children. 284 for( child = node->children ; child ; child = child->next ) 285 { 286 if ( g_strcasecmp( "name", child->name ) == 0) 287 { 288 txu->name = g_memdup( child->text, child->text_len + 1 ); 289 } 290 else if (g_strcasecmp( "screen_name", child->name ) == 0) 291 { 292 txu->screen_name = g_memdup( child->text, child->text_len + 1 ); 275 for (child = node->children; child; child = child->next) { 276 if (g_strcasecmp("name", child->name) == 0) { 277 txu->name = g_memdup(child->text, child->text_len + 1); 278 } else if (g_strcasecmp("screen_name", child->name) == 0) { 279 txu->screen_name = g_memdup(child->text, child->text_len + 1); 293 280 } 294 281 } … … 301 288 * - all <user>s from the <users> element. 302 289 */ 303 static xt_status twitter_xt_get_users( struct xt_node *node, struct twitter_xml_list *txl)290 static xt_status twitter_xt_get_users(struct xt_node *node, struct twitter_xml_list *txl) 304 291 { 305 292 struct twitter_xml_user *txu; … … 311 298 // The root <users> node should hold the list of users <user> 312 299 // Walk over the nodes children. 313 for( child = node->children ; child ; child = child->next ) 314 { 315 if ( g_strcasecmp( "user", child->name ) == 0) 316 { 300 for (child = node->children; child; child = child->next) { 301 if (g_strcasecmp("user", child->name) == 0) { 317 302 txu = g_new0(struct twitter_xml_user, 1); 318 303 twitter_xt_get_user(child, txu); 319 304 // Put the item in the front of the list. 320 txl->list = g_slist_prepend 305 txl->list = g_slist_prepend(txl->list, txu); 321 306 } 322 307 } … … 331 316 * - the next_cursor. 332 317 */ 333 static xt_status twitter_xt_get_user_list( struct xt_node *node, struct twitter_xml_list *txl)318 static xt_status twitter_xt_get_user_list(struct xt_node *node, struct twitter_xml_list *txl) 334 319 { 335 320 struct xt_node *child; … … 340 325 // The root <user_list> node should hold a users <users> element 341 326 // Walk over the nodes children. 342 for( child = node->children ; child ; child = child->next ) 343 { 344 if ( g_strcasecmp( "users", child->name ) == 0) 345 { 327 for (child = node->children; child; child = child->next) { 328 if (g_strcasecmp("users", child->name) == 0) { 346 329 twitter_xt_get_users(child, txl); 347 } 348 else if ( g_strcasecmp( "next_cursor", child->name ) == 0) 349 { 330 } else if (g_strcasecmp("next_cursor", child->name) == 0) { 350 331 twitter_xt_next_cursor(child, txl); 351 332 } … … 369 350 * - the user in a twitter_xml_user struct. 370 351 */ 371 static xt_status twitter_xt_get_status( struct xt_node *node, struct twitter_xml_status *txs)352 static xt_status twitter_xt_get_status(struct xt_node *node, struct twitter_xml_status *txs) 372 353 { 373 354 struct xt_node *child, *rt = NULL; … … 375 356 376 357 // Walk over the nodes children. 377 for( child = node->children ; child ; child = child->next ) 378 { 379 if ( g_strcasecmp( "text", child->name ) == 0) 380 { 381 txs->text = g_memdup( child->text, child->text_len + 1 ); 382 } 383 else if (g_strcasecmp( "truncated", child->name ) == 0 && child->text) 384 { 358 for (child = node->children; child; child = child->next) { 359 if (g_strcasecmp("text", child->name) == 0) { 360 txs->text = g_memdup(child->text, child->text_len + 1); 361 } else if (g_strcasecmp("truncated", child->name) == 0 && child->text) { 385 362 truncated = bool2int(child->text); 386 } 387 else if (g_strcasecmp( "retweeted_status", child->name ) == 0) 388 { 363 } else if (g_strcasecmp("retweeted_status", child->name) == 0) { 389 364 rt = child; 390 } 391 else if (g_strcasecmp( "created_at", child->name ) == 0) 392 { 365 } else if (g_strcasecmp("created_at", child->name) == 0) { 393 366 struct tm parsed; 394 367 395 368 /* Very sensitive to changes to the formatting of 396 369 this field. :-( Also assumes the timezone used 397 370 is UTC since C time handling functions suck. */ 398 if( strptime( child->text, TWITTER_TIME_FORMAT, &parsed ) != NULL ) 399 txs->created_at = mktime_utc( &parsed ); 371 if (strptime(child->text, TWITTER_TIME_FORMAT, &parsed) != NULL) 372 txs->created_at = mktime_utc(&parsed); 373 } else if (g_strcasecmp("user", child->name) == 0) { 374 txs->user = g_new0(struct twitter_xml_user, 1); 375 twitter_xt_get_user(child, txs->user); 376 } else if (g_strcasecmp("id", child->name) == 0) { 377 txs->id = g_ascii_strtoull(child->text, NULL, 10); 378 } else if (g_strcasecmp("in_reply_to_status_id", child->name) == 0) { 379 txs->reply_to = g_ascii_strtoull(child->text, NULL, 10); 400 380 } 401 else if (g_strcasecmp( "user", child->name ) == 0) 402 { 403 txs->user = g_new0(struct twitter_xml_user, 1); 404 twitter_xt_get_user( child, txs->user ); 405 } 406 else if (g_strcasecmp( "id", child->name ) == 0) 407 { 408 txs->id = g_ascii_strtoull (child->text, NULL, 10); 409 } 410 else if (g_strcasecmp( "in_reply_to_status_id", child->name ) == 0) 411 { 412 txs->reply_to = g_ascii_strtoull (child->text, NULL, 10); 413 } 414 } 415 381 } 382 416 383 /* If it's a truncated retweet, get the original because dots suck. */ 417 if (truncated && rt) 418 { 384 if (truncated && rt) { 419 385 struct twitter_xml_status *rtxs = g_new0(struct twitter_xml_status, 1); 420 if (twitter_xt_get_status(rt, rtxs) != XT_HANDLED) 421 { 386 if (twitter_xt_get_status(rt, rtxs) != XT_HANDLED) { 422 387 txs_free(rtxs); 423 388 return XT_HANDLED; 424 389 } 425 390 426 391 g_free(txs->text); 427 392 txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text); 428 393 txs_free(rtxs); 429 394 } 430 395 431 396 return XT_HANDLED; 432 397 } … … 438 403 * - the next_cursor. 439 404 */ 440 static xt_status twitter_xt_get_status_list( struct im_connection *ic, struct xt_node *node, struct twitter_xml_list *txl ) 405 static xt_status twitter_xt_get_status_list(struct im_connection *ic, struct xt_node *node, 406 struct twitter_xml_list *txl) 441 407 { 442 408 struct twitter_xml_status *txs; … … 449 415 // The root <statuses> node should hold the list of statuses <status> 450 416 // Walk over the nodes children. 451 for( child = node->children ; child ; child = child->next ) 452 { 453 if ( g_strcasecmp( "status", child->name ) == 0) 454 { 417 for (child = node->children; child; child = child->next) { 418 if (g_strcasecmp("status", child->name) == 0) { 455 419 txs = g_new0(struct twitter_xml_status, 1); 456 420 twitter_xt_get_status(child, txs); 457 421 // Put the item in the front of the list. 458 txl->list = g_slist_prepend 459 422 txl->list = g_slist_prepend(txl->list, txs); 423 460 424 if (txs->user && txs->user->screen_name && 461 (bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name))) 462 { 425 (bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name))) { 463 426 struct twitter_user_data *tud = bu->data; 464 465 if (txs->id > tud->last_id) 466 { 427 428 if (txs->id > tud->last_id) { 467 429 tud->last_id = txs->id; 468 430 tud->last_time = txs->created_at; 469 431 } 470 432 } 471 } 472 else if ( g_strcasecmp( "next_cursor", child->name ) == 0) 473 { 433 } else if (g_strcasecmp("next_cursor", child->name) == 0) { 474 434 twitter_xt_next_cursor(child, txl); 475 435 } … … 488 448 struct twitter_data *td = ic->proto_data; 489 449 490 char *args[4];450 char *args[4]; 491 451 args[0] = "cursor"; 492 args[1] = g_strdup_printf 452 args[1] = g_strdup_printf("%lld", (long long) next_cursor); 493 453 if (td->home_timeline_id) { 494 454 args[2] = "since_id"; 495 args[3] = g_strdup_printf ("%llu", (long long unsigned int) td->home_timeline_id); 496 } 497 498 twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, td->home_timeline_id ? 4 : 2); 455 args[3] = g_strdup_printf("%llu", (long long unsigned int) td->home_timeline_id); 456 } 457 458 twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, 459 td->home_timeline_id ? 4 : 2); 499 460 500 461 g_free(args[1]); … … 505 466 506 467 static char *twitter_msg_add_id(struct im_connection *ic, 507 468 struct twitter_xml_status *txs, const char *prefix) 508 469 { 509 470 struct twitter_data *td = ic->proto_data; 510 471 char *ret = NULL; 511 512 if (!set_getbool(&ic->acc->set, "show_ids")) 513 { 472 473 if (!set_getbool(&ic->acc->set, "show_ids")) { 514 474 if (*prefix) 515 475 return g_strconcat(prefix, txs->text, NULL); … … 517 477 return NULL; 518 478 } 519 479 520 480 td->log[td->log_id].id = txs->id; 521 481 td->log[td->log_id].bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name); 522 if (txs->reply_to) 523 { 482 if (txs->reply_to) { 524 483 int i; 525 for (i = 0; i < TWITTER_LOG_LENGTH; i ++) 526 if (td->log[i].id == txs->reply_to) 527 { 528 ret = g_strdup_printf( "\002[\002%02d->%02d\002]\002 %s%s", 529 td->log_id, i, prefix, txs->text); 484 for (i = 0; i < TWITTER_LOG_LENGTH; i++) 485 if (td->log[i].id == txs->reply_to) { 486 ret = g_strdup_printf("\002[\002%02d->%02d\002]\002 %s%s", 487 td->log_id, i, prefix, txs->text); 530 488 break; 531 489 } 532 490 } 533 491 if (ret == NULL) 534 ret = g_strdup_printf( "\002[\002%02d\002]\002 %s%s", 535 td->log_id, prefix, txs->text); 492 ret = g_strdup_printf("\002[\002%02d\002]\002 %s%s", td->log_id, prefix, txs->text); 536 493 td->log_id = (td->log_id + 1) % TWITTER_LOG_LENGTH; 537 494 538 495 return ret; 539 496 } … … 545 502 struct twitter_data *td = ic->proto_data; 546 503 GSList *l; 547 548 td->home_timeline_gc = gc = imcb_chat_new( ic, "home/timeline" ); 549 550 name_hint = g_strdup_printf( "%s_%s", td->prefix, ic->acc->user ); 551 imcb_chat_name_hint( gc, name_hint ); 552 g_free( name_hint ); 553 554 for( l = ic->bee->users; l; l = l->next ) 555 { 504 505 td->home_timeline_gc = gc = imcb_chat_new(ic, "home/timeline"); 506 507 name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user); 508 imcb_chat_name_hint(gc, name_hint); 509 g_free(name_hint); 510 511 for (l = ic->bee->users; l; l = l->next) { 556 512 bee_user_t *bu = l->data; 557 if ( bu->ic == ic)558 imcb_chat_add_buddy( td->home_timeline_gc, bu->handle);513 if (bu->ic == ic) 514 imcb_chat_add_buddy(td->home_timeline_gc, bu->handle); 559 515 } 560 516 } … … 563 519 * Function that is called to see the statuses in a groupchat window. 564 520 */ 565 static void twitter_groupchat(struct im_connection *ic, GSList * list)521 static void twitter_groupchat(struct im_connection *ic, GSList * list) 566 522 { 567 523 struct twitter_data *td = ic->proto_data; … … 573 529 if (!td->home_timeline_gc) 574 530 twitter_groupchat_init(ic); 575 531 576 532 gc = td->home_timeline_gc; 577 533 if (!gc->joined) 578 imcb_chat_add_buddy( gc, ic->acc->user ); 579 580 for ( l = list; l ; l = g_slist_next(l) ) 581 { 534 imcb_chat_add_buddy(gc, ic->acc->user); 535 536 for (l = list; l; l = g_slist_next(l)) { 582 537 char *msg; 583 538 584 539 status = l->data; 585 540 if (status->user == NULL || status->text == NULL) … … 587 542 588 543 twitter_add_buddy(ic, status->user->screen_name, status->user->name); 589 544 590 545 strip_html(status->text); 591 546 msg = twitter_msg_add_id(ic, status, ""); 592 547 593 548 // Say it! 594 549 if (g_strcasecmp(td->user, status->user->screen_name) == 0) … … 596 551 else 597 552 imcb_chat_msg(gc, status->user->screen_name, 598 msg ? msg : status->text, 0, status->created_at);599 553 msg ? msg : status->text, 0, status->created_at); 554 600 555 g_free(msg); 601 556 602 557 // Update the home_timeline_id to hold the highest id, so that by the next request 603 558 // we won't pick up the updates already in the list. … … 609 564 * Function that is called to see statuses as private messages. 610 565 */ 611 static void twitter_private_message_chat(struct im_connection *ic, GSList * list)566 static void twitter_private_message_chat(struct im_connection *ic, GSList * list) 612 567 { 613 568 struct twitter_data *td = ic->proto_data; … … 616 571 char from[MAX_STRING]; 617 572 gboolean mode_one; 618 619 mode_one = g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "one" ) == 0; 620 621 if( mode_one ) 622 { 623 g_snprintf( from, sizeof( from ) - 1, "%s_%s", td->prefix, ic->acc->user ); 624 from[MAX_STRING-1] = '\0'; 625 } 626 627 for ( l = list; l ; l = g_slist_next(l) ) 628 { 573 574 mode_one = g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "one") == 0; 575 576 if (mode_one) { 577 g_snprintf(from, sizeof(from) - 1, "%s_%s", td->prefix, ic->acc->user); 578 from[MAX_STRING - 1] = '\0'; 579 } 580 581 for (l = list; l; l = g_slist_next(l)) { 629 582 char *prefix = NULL, *text = NULL; 630 583 631 584 status = l->data; 632 633 strip_html( status->text);634 if ( mode_one)585 586 strip_html(status->text); 587 if (mode_one) 635 588 prefix = g_strdup_printf("\002<\002%s\002>\002 ", 636 589 status->user->screen_name); 637 590 else 638 591 twitter_add_buddy(ic, status->user->screen_name, status->user->name); 639 592 640 593 text = twitter_msg_add_id(ic, status, prefix ? prefix : ""); 641 642 imcb_buddy_msg( ic, 643 mode_one ? from : status->user->screen_name, 644 text ? text : status->text, 645 0, status->created_at ); 646 594 595 imcb_buddy_msg(ic, 596 mode_one ? from : status->user->screen_name, 597 text ? text : status->text, 0, status->created_at); 598 647 599 // Update the home_timeline_id to hold the highest id, so that by the next request 648 600 // we won't pick up the updates already in the list. 649 td->home_timeline_id = MAX(td->home_timeline_id, 650 651 g_free( text);652 g_free( prefix);601 td->home_timeline_id = MAX(td->home_timeline_id, status->id); 602 603 g_free(text); 604 g_free(prefix); 653 605 } 654 606 } … … 665 617 666 618 // Check if the connection is still active. 667 if ( !g_slist_find( twitter_connections, ic ))668 return; 669 619 if (!g_slist_find(twitter_connections, ic)) 620 return; 621 670 622 td = ic->proto_data; 671 623 672 624 // Check if the HTTP request went well. 673 if (req->status_code == 200) 674 { 625 if (req->status_code == 200) { 675 626 td->http_fails = 0; 676 627 if (!(ic->flags & OPT_LOGGED_IN)) 677 628 imcb_connected(ic); 678 } 679 else if (req->status_code == 401) 680 { 681 imcb_error( ic, "Authentication failure" ); 682 imc_logout( ic, FALSE ); 683 return; 684 } 685 else 686 { 629 } else if (req->status_code == 401) { 630 imcb_error(ic, "Authentication failure"); 631 imc_logout(ic, FALSE); 632 return; 633 } else { 687 634 // It didn't go well, output the error and return. 688 635 if (++td->http_fails >= 5) 689 imcb_error(ic, "Could not retrieve " TWITTER_HOME_TIMELINE_URL ": %s", twitter_parse_error(req)); 690 636 imcb_error(ic, "Could not retrieve " TWITTER_HOME_TIMELINE_URL ": %s", 637 twitter_parse_error(req)); 638 691 639 return; 692 640 } … … 696 644 697 645 // Parse the data. 698 parser = xt_new( NULL, txl);699 xt_feed( parser, req->reply_body, req->body_size);646 parser = xt_new(NULL, txl); 647 xt_feed(parser, req->reply_body, req->body_size); 700 648 // The root <statuses> node should hold the list of statuses <status> 701 649 twitter_xt_get_status_list(ic, parser->root, txl); 702 xt_free( parser);650 xt_free(parser); 703 651 704 652 // See if the user wants to see the messages in a groupchat window or as private messages. 705 if (txl->list == NULL) 706 ; 653 if (txl->list == NULL); 707 654 else if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0) 708 655 twitter_groupchat(ic, txl->list); … … 710 657 twitter_private_message_chat(ic, txl->list); 711 658 712 // Free the structure. 659 // Free the structure. 713 660 txl_free(txl); 714 661 } … … 731 678 732 679 // Check if the connection is still active. 733 if ( !g_slist_find( twitter_connections, ic ))734 return; 735 680 if (!g_slist_find(twitter_connections, ic)) 681 return; 682 736 683 td = ic->proto_data; 737 684 738 685 // Check if the HTTP request went well. 739 if (req->status_code == 401) 740 { 741 imcb_error( ic, "Authentication failure" ); 742 imc_logout( ic, FALSE ); 686 if (req->status_code == 401) { 687 imcb_error(ic, "Authentication failure"); 688 imc_logout(ic, FALSE); 743 689 return; 744 690 } else if (req->status_code != 200) { 745 691 // It didn't go well, output the error and return. 746 imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s", twitter_parse_error(req)); 747 imc_logout( ic, TRUE ); 692 imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s", 693 twitter_parse_error(req)); 694 imc_logout(ic, TRUE); 748 695 return; 749 696 } else { 750 697 td->http_fails = 0; 751 698 } 752 753 if( !td->home_timeline_gc && 754 g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "chat" ) == 0 ) 755 twitter_groupchat_init( ic ); 699 700 if (!td->home_timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0) 701 twitter_groupchat_init(ic); 756 702 757 703 txl = g_new0(struct twitter_xml_list, 1); … … 759 705 760 706 // Parse the data. 761 parser = xt_new( NULL, txl);762 xt_feed( parser, req->reply_body, req->body_size);707 parser = xt_new(NULL, txl); 708 xt_feed(parser, req->reply_body, req->body_size); 763 709 764 710 // Get the user list from the parsed xml feed. 765 711 twitter_xt_get_user_list(parser->root, txl); 766 xt_free( parser);712 xt_free(parser); 767 713 768 714 // Add the users as buddies. 769 for ( l = txl->list; l ; l = g_slist_next(l) ) 770 { 715 for (l = txl->list; l; l = g_slist_next(l)) { 771 716 user = l->data; 772 717 twitter_add_buddy(ic, user->screen_name, user->name); … … 774 719 775 720 // if the next_cursor is set to something bigger then 0 there are more friends to gather. 776 if (txl->next_cursor > 0) 777 { 721 if (txl->next_cursor > 0) { 778 722 twitter_get_statuses_friends(ic, txl->next_cursor); 779 } 780 else 781 { 723 } else { 782 724 td->flags |= TWITTER_HAVE_FRIENDS; 783 725 twitter_login_finish(ic); 784 726 } 785 727 786 728 // Free the structure. 787 729 txl_free(txl); … … 793 735 void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor) 794 736 { 795 char *args[2];737 char *args[2]; 796 738 args[0] = "cursor"; 797 args[1] = g_strdup_printf ("%lld", (long long) next_cursor); 798 799 twitter_http(ic, TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, args, 2); 739 args[1] = g_strdup_printf("%lld", (long long) next_cursor); 740 741 twitter_http(ic, TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, args, 742 2); 800 743 801 744 g_free(args[1]); … … 811 754 812 755 // Check if the connection is still active. 813 if ( !g_slist_find( twitter_connections, ic ))756 if (!g_slist_find(twitter_connections, ic)) 814 757 return; 815 758 816 759 td = ic->proto_data; 817 760 td->last_status_id = 0; 818 761 819 762 // Check if the HTTP request went well. 820 763 if (req->status_code != 200) { … … 823 766 return; 824 767 } 825 826 if (req->body_size > 0) 827 { 768 769 if (req->body_size > 0) { 828 770 struct xt_parser *xp = NULL; 829 771 struct xt_node *node; 830 772 831 773 xp = xt_new(NULL, NULL); 832 774 xt_feed(xp, req->reply_body, req->body_size); 833 775 834 776 if ((node = xt_find_node(xp->root, "status")) && 835 777 (node = xt_find_node(node->children, "id")) && node->text) 836 td->last_status_id = g_ascii_strtoull( node->text, NULL, 10);837 778 td->last_status_id = g_ascii_strtoull(node->text, NULL, 10); 779 838 780 xt_free(xp); 839 781 } … … 842 784 /** 843 785 * Function to POST a new status to twitter. 844 */ 786 */ 845 787 void twitter_post_status(struct im_connection *ic, char *msg, guint64 in_reply_to) 846 788 { 847 char *args[4] = {789 char *args[4] = { 848 790 "status", msg, 849 791 "in_reply_to_status_id", … … 851 793 }; 852 794 twitter_http(ic, TWITTER_STATUS_UPDATE_URL, twitter_http_post, ic, 1, 853 795 args, in_reply_to ? 4 : 2); 854 796 g_free(args[3]); 855 797 } … … 861 803 void twitter_direct_messages_new(struct im_connection *ic, char *who, char *msg) 862 804 { 863 char *args[4];805 char *args[4]; 864 806 args[0] = "screen_name"; 865 807 args[1] = who; … … 868 810 // Use the same callback as for twitter_post_status, since it does basically the same. 869 811 twitter_http(ic, TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post, ic, 1, args, 4); 870 // 871 // 812 // g_free(args[1]); 813 // g_free(args[3]); 872 814 } 873 815 874 816 void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create) 875 817 { 876 char *args[2];818 char *args[2]; 877 819 args[0] = "screen_name"; 878 820 args[1] = who; 879 twitter_http(ic, create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL, twitter_http_post, ic, 1, args, 2); 821 twitter_http(ic, create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL, 822 twitter_http_post, ic, 1, args, 2); 880 823 } 881 824 … … 883 826 { 884 827 char *url; 885 url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_DESTROY_URL, (unsigned long long) id, ".xml"); 828 url = 829 g_strdup_printf("%s%llu%s", TWITTER_STATUS_DESTROY_URL, (unsigned long long) id, 830 ".xml"); 886 831 twitter_http(ic, url, twitter_http_post, ic, 1, NULL, 0); 887 832 g_free(url); … … 891 836 { 892 837 char *url; 893 url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_RETWEET_URL, (unsigned long long) id, ".xml"); 838 url = 839 g_strdup_printf("%s%llu%s", TWITTER_STATUS_RETWEET_URL, (unsigned long long) id, 840 ".xml"); 894 841 twitter_http(ic, url, twitter_http_post, ic, 1, NULL, 0); 895 842 g_free(url);
Note: See TracChangeset
for help on using the changeset viewer.