Changeset 5ebff60 for protocols/msn/sb.c
- Timestamp:
- 2015-02-20T22:50:54Z (9 years ago)
- Branches:
- master
- Children:
- 0b9daac, 3d45471, 7733b8c
- Parents:
- af359b4
- git-author:
- Indent <please@…> (19-02-15 05:47:20)
- git-committer:
- dequis <dx@…> (20-02-15 22:50:54)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/msn/sb.c
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 31 31 #include "invitation.h" 32 32 33 static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond);34 static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts);35 static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);36 37 int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ...)33 static gboolean msn_sb_callback(gpointer data, gint source, b_input_condition cond); 34 static int msn_sb_command(struct msn_handler_data *handler, char **cmd, int num_parts); 35 static int msn_sb_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts); 36 37 int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) 38 38 { 39 39 va_list params; … … 41 41 size_t len; 42 42 int st; 43 44 va_start( params, fmt);45 out = g_strdup_vprintf( fmt, params);46 va_end( params);47 48 if ( getenv( "BITLBEE_DEBUG" ) )49 fprintf( stderr, "->SB%d:%s\n", sb->fd, out);50 51 len = strlen( out ); 52 st = write( sb->fd, out, len);53 g_free( out);54 if( st != len )55 {56 msn_sb_destroy( sb);43 44 va_start(params, fmt); 45 out = g_strdup_vprintf(fmt, params); 46 va_end(params); 47 48 if (getenv("BITLBEE_DEBUG")) { 49 fprintf(stderr, "->SB%d:%s\n", sb->fd, out); 50 } 51 52 len = strlen(out); 53 st = write(sb->fd, out, len); 54 g_free(out); 55 if (st != len) { 56 msn_sb_destroy(sb); 57 57 return 0; 58 58 } 59 59 60 60 return 1; 61 61 } 62 62 63 int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m)63 int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m) 64 64 { 65 65 struct msn_data *md = ic->proto_data; … … 67 67 68 68 /* FIXME: *CHECK* the reliability of using spare sb's! */ 69 if( ( sb = msn_sb_spare( ic ) ) ) 70 { 71 debug( "Trying to use a spare switchboard to message %s", m->who ); 72 73 sb->who = g_strdup( m->who ); 74 if( msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, m->who ) ) 75 { 69 if ((sb = msn_sb_spare(ic))) { 70 debug("Trying to use a spare switchboard to message %s", m->who); 71 72 sb->who = g_strdup(m->who); 73 if (msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, m->who)) { 76 74 /* He/She should join the switchboard soon, let's queue the message. */ 77 sb->msgq = g_slist_append( sb->msgq, m);78 return( 1);79 } 80 } 81 82 debug( "Creating a new switchboard to message %s", m->who);83 75 sb->msgq = g_slist_append(sb->msgq, m); 76 return(1); 77 } 78 } 79 80 debug("Creating a new switchboard to message %s", m->who); 81 84 82 /* If we reach this line, there was no spare switchboard, so let's make one. */ 85 if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) ) 86 { 87 g_free( m->who ); 88 g_free( m->text ); 89 g_free( m ); 90 91 return( 0 ); 92 } 93 83 if (!msn_ns_write(ic, -1, "XFR %d SB\r\n", ++md->trId)) { 84 g_free(m->who); 85 g_free(m->text); 86 g_free(m); 87 88 return(0); 89 } 90 94 91 /* And queue the message to md. We'll pick it up when the switchboard comes up. */ 95 md->msgq = g_slist_append( md->msgq, m);96 92 md->msgq = g_slist_append(md->msgq, m); 93 97 94 /* FIXME: If the switchboard creation fails, the message will not be sent. */ 98 99 return( 1);100 } 101 102 struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session)95 96 return(1); 97 } 98 99 struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session) 103 100 { 104 101 struct msn_data *md = ic->proto_data; 105 struct msn_switchboard *sb = g_new0( struct msn_switchboard, 1 ); 106 107 sb->fd = proxy_connect( host, port, msn_sb_connected, sb ); 108 if( sb->fd < 0 ) 109 { 110 g_free( sb ); 111 return( NULL ); 112 } 113 102 struct msn_switchboard *sb = g_new0(struct msn_switchboard, 1); 103 104 sb->fd = proxy_connect(host, port, msn_sb_connected, sb); 105 if (sb->fd < 0) { 106 g_free(sb); 107 return(NULL); 108 } 109 114 110 sb->ic = ic; 115 sb->key = g_strdup( key);111 sb->key = g_strdup(key); 116 112 sb->session = session; 117 118 msn_switchboards = g_slist_append( msn_switchboards, sb);119 md->switchboards = g_slist_append( md->switchboards, sb);120 121 return( sb);122 } 123 124 struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, const char *handle)113 114 msn_switchboards = g_slist_append(msn_switchboards, sb); 115 md->switchboards = g_slist_append(md->switchboards, sb); 116 117 return(sb); 118 } 119 120 struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle) 125 121 { 126 122 struct msn_data *md = ic->proto_data; 127 123 struct msn_switchboard *sb; 128 124 GSList *l; 129 130 for( l = md->switchboards; l; l = l->next ) 131 { 125 126 for (l = md->switchboards; l; l = l->next) { 132 127 sb = l->data; 133 if( sb->who && strcmp( sb->who, handle ) == 0 ) 134 return( sb ); 135 } 136 137 return( NULL ); 138 } 139 140 struct msn_switchboard *msn_sb_by_chat( struct groupchat *c ) 128 if (sb->who && strcmp(sb->who, handle) == 0) { 129 return(sb); 130 } 131 } 132 133 return(NULL); 134 } 135 136 struct msn_switchboard *msn_sb_by_chat(struct groupchat *c) 141 137 { 142 138 struct msn_data *md = c->ic->proto_data; 143 139 struct msn_switchboard *sb; 144 140 GSList *l; 145 146 for( l = md->switchboards; l; l = l->next ) 147 { 141 142 for (l = md->switchboards; l; l = l->next) { 148 143 sb = l->data; 149 if( sb->chat == c ) 150 return( sb ); 151 } 152 153 return( NULL ); 154 } 155 156 struct msn_switchboard *msn_sb_spare( struct im_connection *ic ) 144 if (sb->chat == c) { 145 return(sb); 146 } 147 } 148 149 return(NULL); 150 } 151 152 struct msn_switchboard *msn_sb_spare(struct im_connection *ic) 157 153 { 158 154 struct msn_data *md = ic->proto_data; 159 155 struct msn_switchboard *sb; 160 156 GSList *l; 161 162 for( l = md->switchboards; l; l = l->next ) 163 { 157 158 for (l = md->switchboards; l; l = l->next) { 164 159 sb = l->data; 165 if ( !sb->who && !sb->chat )166 return( sb);167 }168 169 return( NULL ); 170 } 171 172 int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) 173 { 174 if( sb->ready ) 175 {160 if (!sb->who && !sb->chat) { 161 return(sb); 162 } 163 } 164 165 return(NULL); 166 } 167 168 int msn_sb_sendmessage(struct msn_switchboard *sb, char *text) 169 { 170 if (sb->ready) { 176 171 char *buf; 177 172 int i, j; 178 173 179 174 /* Build the message. Convert LF to CR-LF for normal messages. */ 180 if( strcmp( text, TYPING_NOTIFICATION_MESSAGE ) == 0 ) 181 { 182 i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->ic->acc->user ); 183 buf = g_new0( char, i ); 184 i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user ); 185 } 186 else if( strcmp( text, NUDGE_MESSAGE ) == 0 ) 187 { 188 buf = g_strdup( MSN_NUDGE_HEADERS ); 189 i = strlen( buf ); 190 } 191 else if( strcmp( text, SB_KEEPALIVE_MESSAGE ) == 0 ) 192 { 193 buf = g_strdup( MSN_SB_KEEPALIVE_HEADERS ); 194 i = strlen( buf ); 195 } 196 else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 ) 197 { 198 buf = g_strdup( text ); 199 i = strlen( buf ); 200 } 201 else 202 { 203 buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 + 1 ); 204 i = strlen( MSN_MESSAGE_HEADERS ); 205 206 strcpy( buf, MSN_MESSAGE_HEADERS ); 207 for( j = 0; text[j]; j ++ ) 208 { 209 if( text[j] == '\n' ) 175 if (strcmp(text, TYPING_NOTIFICATION_MESSAGE) == 0) { 176 i = strlen(MSN_TYPING_HEADERS) + strlen(sb->ic->acc->user); 177 buf = g_new0(char, i); 178 i = g_snprintf(buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user); 179 } else if (strcmp(text, NUDGE_MESSAGE) == 0) { 180 buf = g_strdup(MSN_NUDGE_HEADERS); 181 i = strlen(buf); 182 } else if (strcmp(text, SB_KEEPALIVE_MESSAGE) == 0) { 183 buf = g_strdup(MSN_SB_KEEPALIVE_HEADERS); 184 i = strlen(buf); 185 } else if (strncmp(text, MSN_INVITE_HEADERS, sizeof(MSN_INVITE_HEADERS) - 1) == 0) { 186 buf = g_strdup(text); 187 i = strlen(buf); 188 } else { 189 buf = g_new0(char, sizeof(MSN_MESSAGE_HEADERS) + strlen(text) * 2 + 1); 190 i = strlen(MSN_MESSAGE_HEADERS); 191 192 strcpy(buf, MSN_MESSAGE_HEADERS); 193 for (j = 0; text[j]; j++) { 194 if (text[j] == '\n') { 210 195 buf[i++] = '\r'; 211 196 } 197 212 198 buf[i++] = text[j]; 213 199 } 214 200 } 215 201 216 202 /* Build the final packet (MSG command + the message). */ 217 if( msn_sb_write( sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf ) ) 218 { 219 g_free( buf ); 203 if (msn_sb_write(sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf)) { 204 g_free(buf); 220 205 return 1; 221 } 222 else 223 { 224 g_free( buf ); 206 } else { 207 g_free(buf); 225 208 return 0; 226 209 } 227 } 228 else if( sb->who ) 229 { 230 struct msn_message *m = g_new0( struct msn_message, 1 ); 231 232 m->who = g_strdup( "" ); 233 m->text = g_strdup( text ); 234 sb->msgq = g_slist_append( sb->msgq, m ); 235 236 return( 1 ); 237 } 238 else 239 { 240 return( 0 ); 241 } 242 } 243 244 struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb ) 210 } else if (sb->who) { 211 struct msn_message *m = g_new0(struct msn_message, 1); 212 213 m->who = g_strdup(""); 214 m->text = g_strdup(text); 215 sb->msgq = g_slist_append(sb->msgq, m); 216 217 return(1); 218 } else { 219 return(0); 220 } 221 } 222 223 struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb) 245 224 { 246 225 struct im_connection *ic = sb->ic; 247 226 struct groupchat *c = NULL; 248 227 char buf[1024]; 249 228 250 229 /* Create the groupchat structure. */ 251 g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); 252 if( sb->who ) 253 c = bee_chat_by_title( ic->bee, ic, sb->who ); 254 if( c && !msn_sb_by_chat( c ) ) 230 g_snprintf(buf, sizeof(buf), "MSN groupchat session %d", sb->session); 231 if (sb->who) { 232 c = bee_chat_by_title(ic->bee, ic, sb->who); 233 } 234 if (c && !msn_sb_by_chat(c)) { 255 235 sb->chat = c; 256 else 257 sb->chat = imcb_chat_new( ic, buf ); 258 236 } else { 237 sb->chat = imcb_chat_new(ic, buf); 238 } 239 259 240 /* Populate the channel. */ 260 if( sb->who ) imcb_chat_add_buddy( sb->chat, sb->who ); 261 imcb_chat_add_buddy( sb->chat, ic->acc->user ); 262 241 if (sb->who) { 242 imcb_chat_add_buddy(sb->chat, sb->who); 243 } 244 imcb_chat_add_buddy(sb->chat, ic->acc->user); 245 263 246 /* And make sure the switchboard doesn't look like a regular chat anymore. */ 264 if( sb->who ) 265 { 266 g_free( sb->who ); 247 if (sb->who) { 248 g_free(sb->who); 267 249 sb->who = NULL; 268 250 } 269 251 270 252 return sb->chat; 271 253 } 272 254 273 void msn_sb_destroy( struct msn_switchboard *sb)255 void msn_sb_destroy(struct msn_switchboard *sb) 274 256 { 275 257 struct im_connection *ic = sb->ic; 276 258 struct msn_data *md = ic->proto_data; 277 278 debug( "Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : "" ); 279 280 msn_msgq_purge( ic, &sb->msgq ); 281 msn_sb_stop_keepalives( sb ); 282 283 if( sb->key ) g_free( sb->key ); 284 if( sb->who ) g_free( sb->who ); 285 286 if( sb->chat ) 287 { 288 imcb_chat_free( sb->chat ); 289 } 290 291 if( sb->handler ) 292 { 293 if( sb->handler->rxq ) g_free( sb->handler->rxq ); 294 if( sb->handler->cmd_text ) g_free( sb->handler->cmd_text ); 295 g_free( sb->handler ); 296 } 297 298 if( sb->inp ) b_event_remove( sb->inp ); 299 closesocket( sb->fd ); 300 301 msn_switchboards = g_slist_remove( msn_switchboards, sb ); 302 md->switchboards = g_slist_remove( md->switchboards, sb ); 303 g_free( sb ); 304 } 305 306 gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) 259 260 debug("Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : ""); 261 262 msn_msgq_purge(ic, &sb->msgq); 263 msn_sb_stop_keepalives(sb); 264 265 if (sb->key) { 266 g_free(sb->key); 267 } 268 if (sb->who) { 269 g_free(sb->who); 270 } 271 272 if (sb->chat) { 273 imcb_chat_free(sb->chat); 274 } 275 276 if (sb->handler) { 277 if (sb->handler->rxq) { 278 g_free(sb->handler->rxq); 279 } 280 if (sb->handler->cmd_text) { 281 g_free(sb->handler->cmd_text); 282 } 283 g_free(sb->handler); 284 } 285 286 if (sb->inp) { 287 b_event_remove(sb->inp); 288 } 289 closesocket(sb->fd); 290 291 msn_switchboards = g_slist_remove(msn_switchboards, sb); 292 md->switchboards = g_slist_remove(md->switchboards, sb); 293 g_free(sb); 294 } 295 296 gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond) 307 297 { 308 298 struct msn_switchboard *sb = data; … … 310 300 struct msn_data *md; 311 301 char buf[1024]; 312 302 313 303 /* Are we still alive? */ 314 if ( !g_slist_find( msn_switchboards, sb ) )304 if (!g_slist_find(msn_switchboards, sb)) { 315 305 return FALSE; 316 306 } 307 317 308 ic = sb->ic; 318 309 md = ic->proto_data; 319 320 if( source != sb->fd ) 321 { 322 debug( "Error %d while connecting to switchboard server", 1 ); 323 msn_sb_destroy( sb ); 310 311 if (source != sb->fd) { 312 debug("Error %d while connecting to switchboard server", 1); 313 msn_sb_destroy(sb); 324 314 return FALSE; 325 315 } 326 316 327 317 /* Prepare the callback */ 328 sb->handler = g_new0( struct msn_handler_data, 1);318 sb->handler = g_new0(struct msn_handler_data, 1); 329 319 sb->handler->fd = sb->fd; 330 sb->handler->rxq = g_new0( char, 1);320 sb->handler->rxq = g_new0(char, 1); 331 321 sb->handler->data = sb; 332 322 sb->handler->exec_command = msn_sb_command; 333 323 sb->handler->exec_message = msn_sb_message; 334 335 if( sb->session == MSN_SB_NEW ) 336 g_snprintf( buf, sizeof( buf ), "USR %d %s;{%s} %s\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key ); 337 else 338 g_snprintf( buf, sizeof( buf ), "ANS %d %s;{%s} %s %d\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key, sb->session ); 339 340 if( msn_sb_write( sb, "%s", buf ) ) 341 sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb ); 342 else 343 debug( "Error %d while connecting to switchboard server", 2 ); 344 324 325 if (sb->session == MSN_SB_NEW) { 326 g_snprintf(buf, sizeof(buf), "USR %d %s;{%s} %s\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key); 327 } else { 328 g_snprintf(buf, sizeof(buf), "ANS %d %s;{%s} %s %d\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key, 329 sb->session); 330 } 331 332 if (msn_sb_write(sb, "%s", buf)) { 333 sb->inp = b_input_add(sb->fd, B_EV_IO_READ, msn_sb_callback, sb); 334 } else { 335 debug("Error %d while connecting to switchboard server", 2); 336 } 337 345 338 return FALSE; 346 339 } 347 340 348 static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond)341 static gboolean msn_sb_callback(gpointer data, gint source, b_input_condition cond) 349 342 { 350 343 struct msn_switchboard *sb = data; 351 344 struct im_connection *ic = sb->ic; 352 345 struct msn_data *md = ic->proto_data; 353 354 if ( msn_handler( sb->handler ) != -1 )346 347 if (msn_handler(sb->handler) != -1) { 355 348 return TRUE; 356 357 if( sb->msgq != NULL ) 358 { 359 time_t now = time( NULL ); 360 361 if( now - md->first_sb_failure > 600 ) 362 { 349 } 350 351 if (sb->msgq != NULL) { 352 time_t now = time(NULL); 353 354 if (now - md->first_sb_failure > 600) { 363 355 /* It's not really the first one, but the start of this "series". 364 356 With this, the warning below will be shown only if this happens … … 368 360 md->sb_failures = 0; 369 361 } 370 371 debug( "Error: Switchboard died");372 if ( ++ md->sb_failures >= 3 )373 imcb_log( 374 "There might be problems delivering your messages.");375 376 if( md->msgq == NULL ) 377 {362 363 debug("Error: Switchboard died"); 364 if (++md->sb_failures >= 3) { 365 imcb_log(ic, "Warning: Many switchboard failures on MSN connection. " 366 "There might be problems delivering your messages."); 367 } 368 369 if (md->msgq == NULL) { 378 370 md->msgq = sb->msgq; 379 } 380 else 381 { 371 } else { 382 372 GSList *l; 383 384 for( l = md->msgq; l->next; l = l->next ); 373 374 for (l = md->msgq; l->next; l = l->next) { 375 ; 376 } 385 377 l->next = sb->msgq; 386 378 } 387 379 sb->msgq = NULL; 388 389 debug( 390 "creating a new switchboard to retry.");391 if ( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) )380 381 debug("Moved queued messages back to the main queue, " 382 "creating a new switchboard to retry."); 383 if (!msn_ns_write(ic, -1, "XFR %d SB\r\n", ++md->trId)) { 392 384 return FALSE; 393 } 394 395 msn_sb_destroy( sb ); 385 } 386 } 387 388 msn_sb_destroy(sb); 396 389 return FALSE; 397 390 } 398 391 399 static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts)392 static int msn_sb_command(struct msn_handler_data *handler, char **cmd, int num_parts) 400 393 { 401 394 struct msn_switchboard *sb = handler->data; 402 395 struct im_connection *ic = sb->ic; 403 404 if( !num_parts ) 405 { 396 397 if (!num_parts) { 406 398 /* Hrrm... Empty command...? Ignore? */ 407 return( 1 ); 408 } 409 410 if( strcmp( cmd[0], "XFR" ) == 0 ) 411 { 412 imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" ); 413 imc_logout( ic, TRUE ); 414 return( 0 ); 415 } 416 else if( strcmp( cmd[0], "USR" ) == 0 ) 417 { 418 if( num_parts < 5 ) 419 { 420 msn_sb_destroy( sb ); 421 return( 0 ); 422 } 423 424 if( strcmp( cmd[2], "OK" ) != 0 ) 425 { 426 msn_sb_destroy( sb ); 427 return( 0 ); 428 } 429 430 if( sb->who ) 431 return msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, sb->who ); 432 else 433 debug( "Just created a switchboard, but I don't know what to do with it." ); 434 } 435 else if( strcmp( cmd[0], "IRO" ) == 0 ) 436 { 399 return(1); 400 } 401 402 if (strcmp(cmd[0], "XFR") == 0) { 403 imcb_error(ic, 404 "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!"); 405 imc_logout(ic, TRUE); 406 return(0); 407 } else if (strcmp(cmd[0], "USR") == 0) { 408 if (num_parts < 5) { 409 msn_sb_destroy(sb); 410 return(0); 411 } 412 413 if (strcmp(cmd[2], "OK") != 0) { 414 msn_sb_destroy(sb); 415 return(0); 416 } 417 418 if (sb->who) { 419 return msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, sb->who); 420 } else { 421 debug("Just created a switchboard, but I don't know what to do with it."); 422 } 423 } else if (strcmp(cmd[0], "IRO") == 0) { 437 424 int num, tot; 438 439 if( num_parts < 6 ) 440 { 441 msn_sb_destroy( sb ); 442 return( 0 ); 443 } 444 445 num = atoi( cmd[2] ); 446 tot = atoi( cmd[3] ); 447 448 if( tot <= 0 ) 449 { 450 msn_sb_destroy( sb ); 451 return( 0 ); 452 } 453 else if( tot > 1 ) 454 { 425 426 if (num_parts < 6) { 427 msn_sb_destroy(sb); 428 return(0); 429 } 430 431 num = atoi(cmd[2]); 432 tot = atoi(cmd[3]); 433 434 if (tot <= 0) { 435 msn_sb_destroy(sb); 436 return(0); 437 } else if (tot > 1) { 455 438 char buf[1024]; 456 439 457 440 /* For as much as I understand this MPOP stuff now, a 458 441 switchboard has two (or more) roster entries per 459 442 participant. One "bare JID" and one JID;UUID. Ignore 460 443 the latter. */ 461 if( !strchr( cmd[4], ';' ) ) 462 { 444 if (!strchr(cmd[4], ';')) { 463 445 /* HACK: Since even 1:1 chats now have >2 participants 464 446 (ourselves included) it gets hard to tell them apart 465 447 from rooms. Let's hope this is enough: */ 466 if( sb->chat == NULL && num != tot ) 467 { 468 g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); 469 sb->chat = imcb_chat_new( ic, buf ); 470 471 g_free( sb->who ); 448 if (sb->chat == NULL && num != tot) { 449 g_snprintf(buf, sizeof(buf), "MSN groupchat session %d", sb->session); 450 sb->chat = imcb_chat_new(ic, buf); 451 452 g_free(sb->who); 472 453 sb->who = NULL; 473 454 } 474 475 if( sb->chat ) 476 imcb_chat_add_buddy( sb->chat, cmd[4] ); 477 } 478 455 456 if (sb->chat) { 457 imcb_chat_add_buddy(sb->chat, cmd[4]); 458 } 459 } 460 479 461 /* We have the full roster, start showing the channel to 480 462 the user. */ 481 if( num == tot && sb->chat ) 482 { 483 imcb_chat_add_buddy( sb->chat, ic->acc->user ); 484 } 485 } 486 } 487 else if( strcmp( cmd[0], "ANS" ) == 0 ) 488 { 489 if( num_parts < 3 ) 490 { 491 msn_sb_destroy( sb ); 492 return( 0 ); 493 } 494 495 if( strcmp( cmd[2], "OK" ) != 0 ) 496 { 497 debug( "Switchboard server sent a negative ANS reply" ); 498 msn_sb_destroy( sb ); 499 return( 0 ); 500 } 501 463 if (num == tot && sb->chat) { 464 imcb_chat_add_buddy(sb->chat, ic->acc->user); 465 } 466 } 467 } else if (strcmp(cmd[0], "ANS") == 0) { 468 if (num_parts < 3) { 469 msn_sb_destroy(sb); 470 return(0); 471 } 472 473 if (strcmp(cmd[2], "OK") != 0) { 474 debug("Switchboard server sent a negative ANS reply"); 475 msn_sb_destroy(sb); 476 return(0); 477 } 478 502 479 sb->ready = 1; 503 504 msn_sb_start_keepalives( sb, FALSE ); 505 } 506 else if( strcmp( cmd[0], "CAL" ) == 0 ) 507 { 508 if( num_parts < 4 || !g_ascii_isdigit( cmd[3][0] ) ) 509 { 510 msn_sb_destroy( sb ); 511 return( 0 ); 512 } 513 514 sb->session = atoi( cmd[3] ); 515 } 516 else if( strcmp( cmd[0], "JOI" ) == 0 ) 517 { 518 if( num_parts < 3 ) 519 { 520 msn_sb_destroy( sb ); 521 return( 0 ); 522 } 523 480 481 msn_sb_start_keepalives(sb, FALSE); 482 } else if (strcmp(cmd[0], "CAL") == 0) { 483 if (num_parts < 4 || !g_ascii_isdigit(cmd[3][0])) { 484 msn_sb_destroy(sb); 485 return(0); 486 } 487 488 sb->session = atoi(cmd[3]); 489 } else if (strcmp(cmd[0], "JOI") == 0) { 490 if (num_parts < 3) { 491 msn_sb_destroy(sb); 492 return(0); 493 } 494 524 495 /* See IRO above. Handle "bare JIDs" only. */ 525 if ( strchr( cmd[1], ';' ) )496 if (strchr(cmd[1], ';')) { 526 497 return 1; 527 528 if( sb->who && g_strcasecmp( cmd[1], sb->who ) == 0 ) 529 {498 } 499 500 if (sb->who && g_strcasecmp(cmd[1], sb->who) == 0) { 530 501 /* The user we wanted to talk to is finally there, let's send the queued messages then. */ 531 502 struct msn_message *m; 532 503 GSList *l; 533 504 int st = 1; 534 535 debug( "%s arrived in the switchboard session, now sending queued message(s)", cmd[1]);536 505 506 debug("%s arrived in the switchboard session, now sending queued message(s)", cmd[1]); 507 537 508 /* Without this, sendmessage() will put everything back on the queue... */ 538 509 sb->ready = 1; 539 540 while( ( l = sb->msgq ) ) 541 { 510 511 while ((l = sb->msgq)) { 542 512 m = l->data; 543 if( st ) 544 { 513 if (st) { 545 514 /* This hack is meant to convert a regular new chat into a groupchat */ 546 if( strcmp( m->text, GROUPCHAT_SWITCHBOARD_MESSAGE ) == 0 ) 547 msn_sb_to_chat( sb ); 548 else 549 st = msn_sb_sendmessage( sb, m->text ); 515 if (strcmp(m->text, GROUPCHAT_SWITCHBOARD_MESSAGE) == 0) { 516 msn_sb_to_chat(sb); 517 } else { 518 st = msn_sb_sendmessage(sb, m->text); 519 } 550 520 } 551 g_free( m->text ); 552 g_free( m->who ); 553 g_free( m ); 554 555 sb->msgq = g_slist_remove( sb->msgq, m ); 556 } 557 558 msn_sb_start_keepalives( sb, FALSE ); 559 560 return( st ); 561 } 562 else if( strcmp( cmd[1], ic->acc->user ) == 0 ) 563 { 521 g_free(m->text); 522 g_free(m->who); 523 g_free(m); 524 525 sb->msgq = g_slist_remove(sb->msgq, m); 526 } 527 528 msn_sb_start_keepalives(sb, FALSE); 529 530 return(st); 531 } else if (strcmp(cmd[1], ic->acc->user) == 0) { 564 532 /* Well, gee thanks. Thanks for letting me know I've arrived.. */ 565 } 566 else if( sb->who ) 567 { 568 debug( "Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1] ); 569 533 } else if (sb->who) { 534 debug("Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1]); 535 570 536 /* This SB is a one-to-one chat right now, but someone else is joining. */ 571 msn_sb_to_chat( sb ); 572 573 imcb_chat_add_buddy( sb->chat, cmd[1] ); 574 } 575 else if( sb->chat ) 576 { 577 imcb_chat_add_buddy( sb->chat, cmd[1] ); 537 msn_sb_to_chat(sb); 538 539 imcb_chat_add_buddy(sb->chat, cmd[1]); 540 } else if (sb->chat) { 541 imcb_chat_add_buddy(sb->chat, cmd[1]); 578 542 sb->ready = 1; 579 } 580 else 581 { 543 } else { 582 544 /* PANIC! */ 583 545 } 584 } 585 else if( strcmp( cmd[0], "MSG" ) == 0 ) 586 { 587 if( num_parts < 4 ) 588 { 589 msn_sb_destroy( sb ); 590 return( 0 ); 591 } 592 593 sb->handler->msglen = atoi( cmd[3] ); 594 595 if( sb->handler->msglen <= 0 ) 596 { 597 debug( "Received a corrupted message on the switchboard, the switchboard will be closed" ); 598 msn_sb_destroy( sb ); 599 return( 0 ); 600 } 601 } 602 else if( strcmp( cmd[0], "NAK" ) == 0 ) 603 { 604 if( sb->who ) 605 { 606 imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who ); 607 } 608 else 609 { 610 imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." ); 611 } 612 } 613 else if( strcmp( cmd[0], "BYE" ) == 0 ) 614 { 615 if( num_parts < 2 ) 616 { 617 msn_sb_destroy( sb ); 618 return( 0 ); 619 } 620 546 } else if (strcmp(cmd[0], "MSG") == 0) { 547 if (num_parts < 4) { 548 msn_sb_destroy(sb); 549 return(0); 550 } 551 552 sb->handler->msglen = atoi(cmd[3]); 553 554 if (sb->handler->msglen <= 0) { 555 debug("Received a corrupted message on the switchboard, the switchboard will be closed"); 556 msn_sb_destroy(sb); 557 return(0); 558 } 559 } else if (strcmp(cmd[0], "NAK") == 0) { 560 if (sb->who) { 561 imcb_log(ic, "The MSN servers could not deliver one of your messages to %s.", sb->who); 562 } else { 563 imcb_log(ic, 564 "The MSN servers could not deliver one of your groupchat messages to all participants."); 565 } 566 } else if (strcmp(cmd[0], "BYE") == 0) { 567 if (num_parts < 2) { 568 msn_sb_destroy(sb); 569 return(0); 570 } 571 621 572 /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */ 622 623 if( sb->who ) 624 { 625 msn_sb_stop_keepalives( sb ); 626 573 574 if (sb->who) { 575 msn_sb_stop_keepalives(sb); 576 627 577 /* This is a single-person chat, and the other person is leaving. */ 628 g_free( sb->who);578 g_free(sb->who); 629 579 sb->who = NULL; 630 580 sb->ready = 0; 631 632 debug( "Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", cmd[1] ); 633 581 582 debug("Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", 583 cmd[1]); 584 634 585 /* We could clean up the switchboard now, but keeping it around 635 586 as a spare for a next conversation sounds more sane to me. 636 587 The server will clean it up when it's idle for too long. */ 637 } 638 else if( sb->chat && !strchr( cmd[1], ';' ) ) 639 { 640 imcb_chat_remove_buddy( sb->chat, cmd[1], "" ); 641 } 642 else 643 { 588 } else if (sb->chat && !strchr(cmd[1], ';')) { 589 imcb_chat_remove_buddy(sb->chat, cmd[1], ""); 590 } else { 644 591 /* PANIC! */ 645 592 } 646 } 647 else if( g_ascii_isdigit( cmd[0][0] ) ) 648 { 649 int num = atoi( cmd[0] ); 650 const struct msn_status_code *err = msn_status_by_number( num ); 651 593 } else if (g_ascii_isdigit(cmd[0][0])) { 594 int num = atoi(cmd[0]); 595 const struct msn_status_code *err = msn_status_by_number(num); 596 652 597 /* If the person is offline, send an offline message instead, 653 598 and don't report an error. */ 654 if ( num == 217 )655 msn_ns_oim_send_queue( ic, &sb->msgq);656 else657 imcb_error( ic, "Error reported by switchboard server: %s", err->text);658 659 if( err->flags & STATUS_SB_FATAL ) 660 {661 msn_sb_destroy( sb);599 if (num == 217) { 600 msn_ns_oim_send_queue(ic, &sb->msgq); 601 } else { 602 imcb_error(ic, "Error reported by switchboard server: %s", err->text); 603 } 604 605 if (err->flags & STATUS_SB_FATAL) { 606 msn_sb_destroy(sb); 662 607 return 0; 663 } 664 else if( err->flags & STATUS_FATAL ) 665 { 666 imc_logout( ic, TRUE ); 608 } else if (err->flags & STATUS_FATAL) { 609 imc_logout(ic, TRUE); 667 610 return 0; 668 } 669 else if( err->flags & STATUS_SB_IM_SPARE ) 670 { 671 if( sb->who ) 672 { 611 } else if (err->flags & STATUS_SB_IM_SPARE) { 612 if (sb->who) { 673 613 /* Apparently some invitation failed. We might want to use this 674 614 board later, so keep it as a spare. */ 675 g_free( sb->who);615 g_free(sb->who); 676 616 sb->who = NULL; 677 617 678 618 /* Also clear the msgq, otherwise someone else might get them. */ 679 msn_msgq_purge( ic, &sb->msgq);680 } 681 619 msn_msgq_purge(ic, &sb->msgq); 620 } 621 682 622 /* Do NOT return 0 here, we want to keep this sb. */ 683 623 } 684 } 685 else 686 { 624 } else { 687 625 /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */ 688 626 } 689 690 return( 1);691 } 692 693 static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)627 628 return(1); 629 } 630 631 static int msn_sb_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts) 694 632 { 695 633 struct msn_switchboard *sb = handler->data; 696 634 struct im_connection *ic = sb->ic; 697 635 char *body; 698 699 if( !num_parts ) 700 return( 1 ); 701 702 if( ( body = strstr( msg, "\r\n\r\n" ) ) ) 636 637 if (!num_parts) { 638 return(1); 639 } 640 641 if ((body = strstr(msg, "\r\n\r\n"))) { 703 642 body += 4; 704 705 if( strcmp( cmd[0], "MSG" ) == 0 ) 706 { 707 char *ct = get_rfc822_header( msg, "Content-Type:", msglen ); 708 709 if( !ct ) 710 return( 1 ); 711 712 if( g_strncasecmp( ct, "text/plain", 10 ) == 0 ) 713 { 714 g_free( ct ); 715 716 if( !body ) 717 return( 1 ); 718 719 if( sb->who ) 720 { 721 imcb_buddy_msg( ic, cmd[1], body, 0, 0 ); 722 } 723 else if( sb->chat ) 724 { 725 imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 ); 726 } 727 else 728 { 643 } 644 645 if (strcmp(cmd[0], "MSG") == 0) { 646 char *ct = get_rfc822_header(msg, "Content-Type:", msglen); 647 648 if (!ct) { 649 return(1); 650 } 651 652 if (g_strncasecmp(ct, "text/plain", 10) == 0) { 653 g_free(ct); 654 655 if (!body) { 656 return(1); 657 } 658 659 if (sb->who) { 660 imcb_buddy_msg(ic, cmd[1], body, 0, 0); 661 } else if (sb->chat) { 662 imcb_chat_msg(sb->chat, cmd[1], body, 0, 0); 663 } else { 729 664 /* PANIC! */ 730 665 } … … 732 667 #if 0 733 668 // Disable MSN ft support for now. 734 else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 ) 735 { 736 char *command = get_rfc822_header( body, "Invitation-Command:", blen ); 737 char *cookie = get_rfc822_header( body, "Invitation-Cookie:", blen ); 669 else if (g_strncasecmp(ct, "text/x-msmsgsinvite", 19) == 0) { 670 char *command = get_rfc822_header(body, "Invitation-Command:", blen); 671 char *cookie = get_rfc822_header(body, "Invitation-Cookie:", blen); 738 672 unsigned int icookie; 739 740 g_free( ct);741 673 674 g_free(ct); 675 742 676 /* Every invite should have both a Command and Cookie header */ 743 if ( !command || !cookie) {744 g_free( command);745 g_free( cookie);746 imcb_log( ic, "Warning: No command or cookie from %s", sb->who);677 if (!command || !cookie) { 678 g_free(command); 679 g_free(cookie); 680 imcb_log(ic, "Warning: No command or cookie from %s", sb->who); 747 681 return 1; 748 682 } 749 750 icookie = strtoul( cookie, NULL, 10);751 g_free( cookie);752 753 if ( g_strncasecmp( command, "INVITE", 6 ) == 0) {754 msn_invitation_invite( sb, cmd[1], icookie, body, blen);755 } else if ( g_strncasecmp( command, "ACCEPT", 6 ) == 0) {756 msn_invitation_accept( sb, cmd[1], icookie, body, blen);757 } else if ( g_strncasecmp( command, "CANCEL", 6 ) == 0) {758 msn_invitation_cancel( sb, cmd[1], icookie, body, blen);683 684 icookie = strtoul(cookie, NULL, 10); 685 g_free(cookie); 686 687 if (g_strncasecmp(command, "INVITE", 6) == 0) { 688 msn_invitation_invite(sb, cmd[1], icookie, body, blen); 689 } else if (g_strncasecmp(command, "ACCEPT", 6) == 0) { 690 msn_invitation_accept(sb, cmd[1], icookie, body, blen); 691 } else if (g_strncasecmp(command, "CANCEL", 6) == 0) { 692 msn_invitation_cancel(sb, cmd[1], icookie, body, blen); 759 693 } else { 760 imcb_log( 761 "command %s from %s", command, sb->who);762 } 763 764 g_free( command);694 imcb_log(ic, "Warning: Received invalid invitation with " 695 "command %s from %s", command, sb->who); 696 } 697 698 g_free(command); 765 699 } 766 700 #endif 767 else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 768 { 701 else if (g_strncasecmp(ct, "application/x-msnmsgrp2p", 24) == 0) { 769 702 /* Not currently implemented. Don't warn about it since 770 703 this seems to be used for avatars now. */ 771 g_free( ct ); 772 } 773 else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 ) 774 { 775 char *who = get_rfc822_header( msg, "TypingUser:", msglen ); 776 777 if( who ) 778 { 779 imcb_buddy_typing( ic, who, OPT_TYPING ); 780 g_free( who ); 781 } 782 783 g_free( ct ); 784 } 785 else 786 { 787 g_free( ct ); 788 } 789 } 790 791 return( 1 ); 792 } 793 794 static gboolean msn_sb_keepalive( gpointer data, gint source, b_input_condition cond ) 704 g_free(ct); 705 } else if (g_strncasecmp(ct, "text/x-msmsgscontrol", 20) == 0) { 706 char *who = get_rfc822_header(msg, "TypingUser:", msglen); 707 708 if (who) { 709 imcb_buddy_typing(ic, who, OPT_TYPING); 710 g_free(who); 711 } 712 713 g_free(ct); 714 } else { 715 g_free(ct); 716 } 717 } 718 719 return(1); 720 } 721 722 static gboolean msn_sb_keepalive(gpointer data, gint source, b_input_condition cond) 795 723 { 796 724 struct msn_switchboard *sb = data; 797 return sb->ready && msn_sb_sendmessage( sb, SB_KEEPALIVE_MESSAGE ); 798 } 799 800 void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial ) 725 726 return sb->ready && msn_sb_sendmessage(sb, SB_KEEPALIVE_MESSAGE); 727 } 728 729 void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial) 801 730 { 802 731 bee_user_t *bu; 803 804 if( sb && sb->who && sb->keepalive == 0 && 805 ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) && 806 !( bu->flags & BEE_USER_ONLINE ) && 807 set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) ) 808 { 809 if( initial ) 810 msn_sb_keepalive( sb, 0, 0 ); 811 812 sb->keepalive = b_timeout_add( 20000, msn_sb_keepalive, sb ); 813 } 814 } 815 816 void msn_sb_stop_keepalives( struct msn_switchboard *sb ) 817 { 818 if( sb && sb->keepalive > 0 ) 819 { 820 b_event_remove( sb->keepalive ); 732 733 if (sb && sb->who && sb->keepalive == 0 && 734 (bu = bee_user_by_handle(sb->ic->bee, sb->ic, sb->who)) && 735 !(bu->flags & BEE_USER_ONLINE) && 736 set_getbool(&sb->ic->acc->set, "switchboard_keepalives")) { 737 if (initial) { 738 msn_sb_keepalive(sb, 0, 0); 739 } 740 741 sb->keepalive = b_timeout_add(20000, msn_sb_keepalive, sb); 742 } 743 } 744 745 void msn_sb_stop_keepalives(struct msn_switchboard *sb) 746 { 747 if (sb && sb->keepalive > 0) { 748 b_event_remove(sb->keepalive); 821 749 sb->keepalive = 0; 822 750 }
Note: See TracChangeset
for help on using the changeset viewer.