Changeset 5ebff60 for protocols/jabber
- Timestamp:
- 2015-02-20T22:50:54Z (10 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)
- Location:
- protocols/jabber
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/jabber/conference.c
raf359b4 r5ebff60 25 25 #include "sha1.h" 26 26 27 static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig);28 29 struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password)27 static xt_status jabber_chat_join_failed(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 28 29 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password) 30 30 { 31 31 struct jabber_chat *jc; … … 33 33 struct groupchat *c; 34 34 char *roomjid; 35 36 roomjid = g_strdup_printf( "%s/%s", room, nick);37 node = xt_new_node( "x", NULL, NULL);38 xt_add_attr( node, "xmlns", XMLNS_MUC);39 if ( password )40 xt_add_child( node, xt_new_node( "password", password, NULL ));41 node = jabber_make_packet( "presence", NULL, roomjid, node );42 jabber_cache_add( ic, node, jabber_chat_join_failed);43 44 if( !jabber_write_packet( ic, node ) ) 45 {46 g_free( roomjid);35 36 roomjid = g_strdup_printf("%s/%s", room, nick); 37 node = xt_new_node("x", NULL, NULL); 38 xt_add_attr(node, "xmlns", XMLNS_MUC); 39 if (password) { 40 xt_add_child(node, xt_new_node("password", password, NULL)); 41 } 42 node = jabber_make_packet("presence", NULL, roomjid, node); 43 jabber_cache_add(ic, node, jabber_chat_join_failed); 44 45 if (!jabber_write_packet(ic, node)) { 46 g_free(roomjid); 47 47 return NULL; 48 48 } 49 50 jc = g_new0( struct jabber_chat, 1 ); 51 jc->name = jabber_normalize( room ); 52 53 if( ( jc->me = jabber_buddy_add( ic, roomjid ) ) == NULL ) 54 { 55 g_free( roomjid ); 56 g_free( jc->name ); 57 g_free( jc ); 49 50 jc = g_new0(struct jabber_chat, 1); 51 jc->name = jabber_normalize(room); 52 53 if ((jc->me = jabber_buddy_add(ic, roomjid)) == NULL) { 54 g_free(roomjid); 55 g_free(jc->name); 56 g_free(jc); 58 57 return NULL; 59 58 } 60 59 61 60 /* roomjid isn't normalized yet, and we need an original version 62 61 of the nick to send a proper presence update. */ 63 62 jc->my_full_jid = roomjid; 64 65 c = imcb_chat_new( ic, room);63 64 c = imcb_chat_new(ic, room); 66 65 c->data = jc; 67 66 68 67 return c; 69 68 } 70 69 71 struct groupchat *jabber_chat_with( struct im_connection *ic, char *who)70 struct groupchat *jabber_chat_with(struct im_connection *ic, char *who) 72 71 { 73 72 struct jabber_data *jd = ic->proto_data; … … 77 76 double now = gettime(); 78 77 char *uuid, *rjid, *cserv; 79 80 sha1_init( &sum);81 sha1_append( &sum, (uint8_t*) ic->acc->user, strlen( ic->acc->user ));82 sha1_append( &sum, (uint8_t*) &now, sizeof( now ));83 sha1_append( &sum, (uint8_t*) who, strlen( who ));84 uuid = sha1_random_uuid( &sum);85 86 if ( jd->flags & JFLAG_GTALK )87 cserv = g_strdup( "groupchat.google.com");88 else78 79 sha1_init(&sum); 80 sha1_append(&sum, (uint8_t *) ic->acc->user, strlen(ic->acc->user)); 81 sha1_append(&sum, (uint8_t *) &now, sizeof(now)); 82 sha1_append(&sum, (uint8_t *) who, strlen(who)); 83 uuid = sha1_random_uuid(&sum); 84 85 if (jd->flags & JFLAG_GTALK) { 86 cserv = g_strdup("groupchat.google.com"); 87 } else { 89 88 /* Guess... */ 90 cserv = g_strdup_printf( "conference.%s", jd->server ); 91 92 rjid = g_strdup_printf( "private-chat-%s@%s", uuid, cserv ); 93 g_free( uuid ); 94 g_free( cserv ); 95 96 c = jabber_chat_join( ic, rjid, jd->username, NULL ); 97 g_free( rjid ); 98 if( c == NULL ) 89 cserv = g_strdup_printf("conference.%s", jd->server); 90 } 91 92 rjid = g_strdup_printf("private-chat-%s@%s", uuid, cserv); 93 g_free(uuid); 94 g_free(cserv); 95 96 c = jabber_chat_join(ic, rjid, jd->username, NULL); 97 g_free(rjid); 98 if (c == NULL) { 99 99 return NULL; 100 100 } 101 101 102 jc = c->data; 102 jc->invite = g_strdup( who);103 103 jc->invite = g_strdup(who); 104 104 105 return c; 105 106 } 106 107 107 static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig)108 static xt_status jabber_chat_join_failed(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 108 109 { 109 110 struct jabber_error *err; 110 111 struct jabber_buddy *bud; 111 112 char *room; 112 113 room = xt_find_attr( orig, "to");114 bud = jabber_buddy_by_jid( ic, room, 0);115 err = jabber_error_parse( xt_find_node( node->children, "error" ), XMLNS_STANZA_ERROR);116 if ( err )117 {118 imcb_error( ic, "Error joining groupchat %s: %s%s%s", room, err->code,119 err->text ? ": " : "", err->text ? err->text : "");120 jabber_error_free( err );121 }122 if( bud )123 jabber_chat_free( jabber_chat_by_jid( ic, bud->bare_jid ) );124 113 114 room = xt_find_attr(orig, "to"); 115 bud = jabber_buddy_by_jid(ic, room, 0); 116 err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR); 117 if (err) { 118 imcb_error(ic, "Error joining groupchat %s: %s%s%s", room, err->code, 119 err->text ? ": " : "", err->text ? err->text : ""); 120 jabber_error_free(err); 121 } 122 if (bud) { 123 jabber_chat_free(jabber_chat_by_jid(ic, bud->bare_jid)); 124 } 125 125 126 return XT_HANDLED; 126 127 } 127 128 128 struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name)129 { 130 char *normalized = jabber_normalize( name);129 struct groupchat *jabber_chat_by_jid(struct im_connection *ic, const char *name) 130 { 131 char *normalized = jabber_normalize(name); 131 132 GSList *l; 132 133 struct groupchat *ret; 133 134 struct jabber_chat *jc; 134 135 for( l = ic->groupchats; l; l = l->next ) 136 { 135 136 for (l = ic->groupchats; l; l = l->next) { 137 137 ret = l->data; 138 138 jc = ret->data; 139 if ( strcmp( normalized, jc->name ) == 0 )139 if (strcmp(normalized, jc->name) == 0) { 140 140 break; 141 } 142 g_free( normalized ); 143 141 } 142 } 143 g_free(normalized); 144 144 145 return l ? ret : NULL; 145 146 } 146 147 147 void jabber_chat_free( struct groupchat *c)148 void jabber_chat_free(struct groupchat *c) 148 149 { 149 150 struct jabber_chat *jc = c->data; 150 151 jabber_buddy_remove_bare( c->ic, jc->name);152 153 g_free( jc->my_full_jid);154 g_free( jc->name);155 g_free( jc->invite);156 g_free( jc);157 158 imcb_chat_free( c);159 } 160 161 int jabber_chat_msg( struct groupchat *c, char *message, int flags)151 152 jabber_buddy_remove_bare(c->ic, jc->name); 153 154 g_free(jc->my_full_jid); 155 g_free(jc->name); 156 g_free(jc->invite); 157 g_free(jc); 158 159 imcb_chat_free(c); 160 } 161 162 int jabber_chat_msg(struct groupchat *c, char *message, int flags) 162 163 { 163 164 struct im_connection *ic = c->ic; 164 165 struct jabber_chat *jc = c->data; 165 166 struct xt_node *node; 166 167 167 168 jc->flags |= JCFLAG_MESSAGE_SENT; 168 169 node = xt_new_node( "body", message, NULL ); 170 node = jabber_make_packet( "message", "groupchat", jc->name, node ); 171 172 if( !jabber_write_packet( ic, node ) ) 173 { 174 xt_free_node( node ); 169 170 node = xt_new_node("body", message, NULL); 171 node = jabber_make_packet("message", "groupchat", jc->name, node); 172 173 if (!jabber_write_packet(ic, node)) { 174 xt_free_node(node); 175 175 return 0; 176 176 } 177 xt_free_node( node);178 177 xt_free_node(node); 178 179 179 return 1; 180 180 } 181 181 182 int jabber_chat_topic( struct groupchat *c, char *topic)182 int jabber_chat_topic(struct groupchat *c, char *topic) 183 183 { 184 184 struct im_connection *ic = c->ic; 185 185 struct jabber_chat *jc = c->data; 186 186 struct xt_node *node; 187 188 node = xt_new_node( "subject", topic, NULL ); 189 node = jabber_make_packet( "message", "groupchat", jc->name, node ); 190 191 if( !jabber_write_packet( ic, node ) ) 192 { 193 xt_free_node( node ); 187 188 node = xt_new_node("subject", topic, NULL); 189 node = jabber_make_packet("message", "groupchat", jc->name, node); 190 191 if (!jabber_write_packet(ic, node)) { 192 xt_free_node(node); 194 193 return 0; 195 194 } 196 xt_free_node( node);197 195 xt_free_node(node); 196 198 197 return 1; 199 198 } 200 199 201 int jabber_chat_leave( struct groupchat *c, const char *reason)200 int jabber_chat_leave(struct groupchat *c, const char *reason) 202 201 { 203 202 struct im_connection *ic = c->ic; 204 203 struct jabber_chat *jc = c->data; 205 204 struct xt_node *node; 206 207 node = xt_new_node( "x", NULL, NULL ); 208 xt_add_attr( node, "xmlns", XMLNS_MUC ); 209 node = jabber_make_packet( "presence", "unavailable", jc->my_full_jid, node ); 210 211 if( !jabber_write_packet( ic, node ) ) 212 { 213 xt_free_node( node ); 205 206 node = xt_new_node("x", NULL, NULL); 207 xt_add_attr(node, "xmlns", XMLNS_MUC); 208 node = jabber_make_packet("presence", "unavailable", jc->my_full_jid, node); 209 210 if (!jabber_write_packet(ic, node)) { 211 xt_free_node(node); 214 212 return 0; 215 213 } 216 xt_free_node( node);217 214 xt_free_node(node); 215 218 216 return 1; 219 217 } 220 218 221 void jabber_chat_invite( struct groupchat *c, char *who, char *message)219 void jabber_chat_invite(struct groupchat *c, char *who, char *message) 222 220 { 223 221 struct xt_node *node; … … 225 223 struct jabber_chat *jc = c->data; 226 224 227 node = xt_new_node( "reason", message, NULL );228 229 node = xt_new_node( "invite", NULL, node);230 xt_add_attr( node, "to", who );231 232 node = xt_new_node( "x", NULL, node );233 xt_add_attr( node, "xmlns", XMLNS_MUC_USER );234 235 node = jabber_make_packet( "message", NULL, jc->name, node );236 237 jabber_write_packet( ic, node );238 239 xt_free_node( node);225 node = xt_new_node("reason", message, NULL); 226 227 node = xt_new_node("invite", NULL, node); 228 xt_add_attr(node, "to", who); 229 230 node = xt_new_node("x", NULL, node); 231 xt_add_attr(node, "xmlns", XMLNS_MUC_USER); 232 233 node = jabber_make_packet("message", NULL, jc->name, node); 234 235 jabber_write_packet(ic, node); 236 237 xt_free_node(node); 240 238 } 241 239 … … 244 242 parameters so we won't have to repeat too many things done by the caller 245 243 already. */ 246 void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node)244 void jabber_chat_pkt_presence(struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node) 247 245 { 248 246 struct groupchat *chat; 249 247 struct xt_node *c; 250 char *type = xt_find_attr( node, "type");248 char *type = xt_find_attr(node, "type"); 251 249 struct jabber_data *jd = ic->proto_data; 252 250 struct jabber_chat *jc; 253 251 char *s; 254 255 if( ( chat = jabber_chat_by_jid( ic, bud->bare_jid ) ) == NULL ) 256 { 252 253 if ((chat = jabber_chat_by_jid(ic, bud->bare_jid)) == NULL) { 257 254 /* How could this happen?? We could do kill( self, 11 ) 258 255 now or just wait for the OS to do it. :-) */ 259 256 return; 260 257 } 261 258 262 259 jc = chat->data; 263 264 if( type == NULL && !( bud->flags & JBFLAG_IS_CHATROOM ) ) 265 { 260 261 if (type == NULL && !(bud->flags & JBFLAG_IS_CHATROOM)) { 266 262 bud->flags |= JBFLAG_IS_CHATROOM; 267 263 /* If this one wasn't set yet, this buddy just joined the chat. 268 264 Slightly hackish way of finding out eh? ;-) */ 269 265 270 266 /* This is pretty messy... Here it sets ext_jid to the real 271 267 JID of the participant. Works for non-anonymized channels. 272 268 Might break if someone joins a chat twice, though. */ 273 for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) 274 if( ( s = xt_find_attr( c, "xmlns" ) ) && 275 ( strcmp( s, XMLNS_MUC_USER ) == 0 ) ) 276 { 269 for (c = node->children; (c = xt_find_node(c, "x")); c = c->next) { 270 if ((s = xt_find_attr(c, "xmlns")) && 271 (strcmp(s, XMLNS_MUC_USER) == 0)) { 277 272 struct xt_node *item; 278 279 item = xt_find_node( c->children, "item" ); 280 if( ( s = xt_find_attr( item, "jid" ) ) ) 281 { 273 274 item = xt_find_node(c->children, "item"); 275 if ((s = xt_find_attr(item, "jid"))) { 282 276 /* Yay, found what we need. :-) */ 283 bud->ext_jid = jabber_normalize( s);277 bud->ext_jid = jabber_normalize(s); 284 278 break; 285 279 } 286 280 } 287 281 } 282 288 283 /* Make up some other handle, if necessary. */ 289 if( bud->ext_jid == NULL ) 290 { 291 if( bud == jc->me ) 292 { 293 bud->ext_jid = g_strdup( jd->me ); 294 } 295 else 296 { 284 if (bud->ext_jid == NULL) { 285 if (bud == jc->me) { 286 bud->ext_jid = g_strdup(jd->me); 287 } else { 297 288 int i; 298 289 299 290 /* Don't want the nick to be at the end, so let's 300 291 think of some slightly different notation to use 301 292 for anonymous groupchat participants in BitlBee. */ 302 bud->ext_jid = g_strdup_printf( "%s=%s", bud->resource, bud->bare_jid);303 293 bud->ext_jid = g_strdup_printf("%s=%s", bud->resource, bud->bare_jid); 294 304 295 /* And strip any unwanted characters. */ 305 for ( i = 0; bud->resource[i]; i ++ )306 if ( bud->ext_jid[i] == '=' || bud->ext_jid[i] == '@' )296 for (i = 0; bud->resource[i]; i++) { 297 if (bud->ext_jid[i] == '=' || bud->ext_jid[i] == '@') { 307 298 bud->ext_jid[i] = '_'; 308 299 } 300 } 301 309 302 /* Some program-specific restrictions. */ 310 imcb_clean_handle( ic, bud->ext_jid);303 imcb_clean_handle(ic, bud->ext_jid); 311 304 } 312 305 bud->flags |= JBFLAG_IS_ANONYMOUS; 313 306 } 314 315 if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS ) 316 { 307 308 if (bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS) { 317 309 /* If JIDs are anonymized, add them to the local 318 310 list for the duration of this chat. */ 319 imcb_add_buddy( ic, bud->ext_jid, NULL ); 320 imcb_buddy_nick_hint( ic, bud->ext_jid, bud->resource ); 321 } 322 323 if( bud == jc->me && jc->invite != NULL ) 324 { 325 char *msg = g_strdup_printf( "Please join me in room %s", jc->name ); 326 jabber_chat_invite( chat, jc->invite, msg ); 327 g_free( jc->invite ); 328 g_free( msg ); 311 imcb_add_buddy(ic, bud->ext_jid, NULL); 312 imcb_buddy_nick_hint(ic, bud->ext_jid, bud->resource); 313 } 314 315 if (bud == jc->me && jc->invite != NULL) { 316 char *msg = g_strdup_printf("Please join me in room %s", jc->name); 317 jabber_chat_invite(chat, jc->invite, msg); 318 g_free(jc->invite); 319 g_free(msg); 329 320 jc->invite = NULL; 330 321 } 331 332 s = strchr( bud->ext_jid, '/' ); 333 if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */ 334 imcb_chat_add_buddy( chat, bud->ext_jid ); 335 if( s ) *s = '/'; 336 } 337 else if( type ) /* type can only be NULL or "unavailable" in this function */ 338 { 339 if( ( bud->flags & JBFLAG_IS_CHATROOM ) && bud->ext_jid ) 340 { 341 s = strchr( bud->ext_jid, '/' ); 342 if( s ) *s = 0; 343 imcb_chat_remove_buddy( chat, bud->ext_jid, NULL ); 344 if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS ) 345 imcb_remove_buddy( ic, bud->ext_jid, NULL ); 346 if( s ) *s = '/'; 347 } 348 349 if( bud == jc->me ) 350 jabber_chat_free( chat ); 351 } 352 } 353 354 void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ) 355 { 356 struct xt_node *subject = xt_find_node( node->children, "subject" ); 357 struct xt_node *body = xt_find_node( node->children, "body" ); 358 struct groupchat *chat = bud ? jabber_chat_by_jid( ic, bud->bare_jid ) : NULL; 322 323 s = strchr(bud->ext_jid, '/'); 324 if (s) { 325 *s = 0; /* Should NEVER be NULL, but who knows... */ 326 } 327 imcb_chat_add_buddy(chat, bud->ext_jid); 328 if (s) { 329 *s = '/'; 330 } 331 } else if (type) { /* type can only be NULL or "unavailable" in this function */ 332 if ((bud->flags & JBFLAG_IS_CHATROOM) && bud->ext_jid) { 333 s = strchr(bud->ext_jid, '/'); 334 if (s) { 335 *s = 0; 336 } 337 imcb_chat_remove_buddy(chat, bud->ext_jid, NULL); 338 if (bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS) { 339 imcb_remove_buddy(ic, bud->ext_jid, NULL); 340 } 341 if (s) { 342 *s = '/'; 343 } 344 } 345 346 if (bud == jc->me) { 347 jabber_chat_free(chat); 348 } 349 } 350 } 351 352 void jabber_chat_pkt_message(struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node) 353 { 354 struct xt_node *subject = xt_find_node(node->children, "subject"); 355 struct xt_node *body = xt_find_node(node->children, "body"); 356 struct groupchat *chat = bud ? jabber_chat_by_jid(ic, bud->bare_jid) : NULL; 359 357 struct jabber_chat *jc = chat ? chat->data : NULL; 360 358 char *s; 361 362 if( subject && chat ) 363 { 364 s = bud ? strchr( bud->ext_jid, '/' ) : NULL; 365 if( s ) *s = 0; 366 imcb_chat_topic( chat, bud ? bud->ext_jid : NULL, subject->text_len > 0 ? 367 subject->text : NULL, jabber_get_timestamp( node ) ); 368 if( s ) *s = '/'; 369 } 370 371 if( bud == NULL || ( jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me ) ) 372 { 359 360 if (subject && chat) { 361 s = bud ? strchr(bud->ext_jid, '/') : NULL; 362 if (s) { 363 *s = 0; 364 } 365 imcb_chat_topic(chat, bud ? bud->ext_jid : NULL, subject->text_len > 0 ? 366 subject->text : NULL, jabber_get_timestamp(node)); 367 if (s) { 368 *s = '/'; 369 } 370 } 371 372 if (bud == NULL || (jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me)) { 373 373 char *nick; 374 375 if ( body == NULL || body->text_len == 0 )374 375 if (body == NULL || body->text_len == 0) { 376 376 /* Meh. Empty messages aren't very interesting, no matter 377 377 how much some servers love to send them. */ 378 378 return; 379 380 s = xt_find_attr( node, "from" ); /* pkt_message() already NULL-checked this one. */ 381 nick = strchr( s, '/' );382 if( nick )383 {379 } 380 381 s = xt_find_attr(node, "from"); /* pkt_message() already NULL-checked this one. */ 382 nick = strchr(s, '/'); 383 if (nick) { 384 384 /* If this message included a resource/nick we don't know, 385 385 we might still know the groupchat itself. */ 386 386 *nick = 0; 387 chat = jabber_chat_by_jid( ic, s);387 chat = jabber_chat_by_jid(ic, s); 388 388 *nick = '/'; 389 390 nick ++; 391 } 392 else 393 { 389 390 nick++; 391 } else { 394 392 /* message.c uses the EXACT_JID option, so bud should 395 393 always be NULL here for bare JIDs. */ 396 chat = jabber_chat_by_jid( ic, s ); 397 } 398 399 if( nick == NULL ) 400 { 394 chat = jabber_chat_by_jid(ic, s); 395 } 396 397 if (nick == NULL) { 401 398 /* This is fine, the groupchat itself isn't in jd->buddies. */ 402 if( chat ) 403 imcb_chat_log( chat, "From conference server: %s", body->text ); 404 else 405 imcb_log( ic, "System message from unknown groupchat %s: %s", s, body->text ); 406 } 407 else 408 { 399 if (chat) { 400 imcb_chat_log(chat, "From conference server: %s", body->text); 401 } else { 402 imcb_log(ic, "System message from unknown groupchat %s: %s", s, body->text); 403 } 404 } else { 409 405 /* This can happen too, at least when receiving a backlog when 410 406 just joining a channel. */ 411 if( chat ) 412 imcb_chat_log( chat, "Message from unknown participant %s: %s", nick, body->text ); 413 else 414 imcb_log( ic, "Groupchat message from unknown JID %s: %s", s, body->text ); 415 } 416 407 if (chat) { 408 imcb_chat_log(chat, "Message from unknown participant %s: %s", nick, body->text); 409 } else { 410 imcb_log(ic, "Groupchat message from unknown JID %s: %s", s, body->text); 411 } 412 } 413 417 414 return; 418 } 419 else if( chat == NULL ) 420 { 415 } else if (chat == NULL) { 421 416 /* How could this happen?? We could do kill( self, 11 ) 422 417 now or just wait for the OS to do it. :-) */ 423 418 return; 424 419 } 425 if( body && body->text_len > 0 ) 426 { 427 s = strchr( bud->ext_jid, '/' ); 428 if( s ) *s = 0; 429 imcb_chat_msg( chat, bud->ext_jid, body->text, 0, jabber_get_timestamp( node ) ); 430 if( s ) *s = '/'; 431 } 432 } 420 if (body && body->text_len > 0) { 421 s = strchr(bud->ext_jid, '/'); 422 if (s) { 423 *s = 0; 424 } 425 imcb_chat_msg(chat, bud->ext_jid, body->text, 0, jabber_get_timestamp(node)); 426 if (s) { 427 *s = '/'; 428 } 429 } 430 } -
protocols/jabber/io.c
raf359b4 r5ebff60 25 25 #include "ssl_client.h" 26 26 27 static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition cond);28 static gboolean jabber_write_queue( struct im_connection *ic);29 30 int jabber_write_packet( struct im_connection *ic, struct xt_node *node)27 static gboolean jabber_write_callback(gpointer data, gint fd, b_input_condition cond); 28 static gboolean jabber_write_queue(struct im_connection *ic); 29 30 int jabber_write_packet(struct im_connection *ic, struct xt_node *node) 31 31 { 32 32 char *buf; 33 33 int st; 34 35 buf = xt_to_string( node);36 st = jabber_write( ic, buf, strlen( buf ));37 g_free( buf);38 34 35 buf = xt_to_string(node); 36 st = jabber_write(ic, buf, strlen(buf)); 37 g_free(buf); 38 39 39 return st; 40 40 } 41 41 42 int jabber_write( struct im_connection *ic, char *buf, int len)42 int jabber_write(struct im_connection *ic, char *buf, int len) 43 43 { 44 44 struct jabber_data *jd = ic->proto_data; 45 45 gboolean ret; 46 47 if( jd->flags & JFLAG_XMLCONSOLE && !( ic->flags & OPT_LOGGING_OUT ) ) 48 { 46 47 if (jd->flags & JFLAG_XMLCONSOLE && !(ic->flags & OPT_LOGGING_OUT)) { 49 48 char *msg, *s; 50 51 msg = g_strdup_printf( "TX: %s", buf);49 50 msg = g_strdup_printf("TX: %s", buf); 52 51 /* Don't include auth info in XML logs. */ 53 if( strncmp( msg, "TX: <auth ", 10 ) == 0 && ( s = strchr( msg, '>' ) ) ) 54 { 52 if (strncmp(msg, "TX: <auth ", 10) == 0 && (s = strchr(msg, '>'))) { 55 53 s++; 56 while ( *s && *s != '<' )54 while (*s && *s != '<') { 57 55 *(s++) = '*'; 58 }59 imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 );60 g_free( msg);61 }62 63 if( jd->tx_len == 0 ) 64 {56 } 57 } 58 imcb_buddy_msg(ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0); 59 g_free(msg); 60 } 61 62 if (jd->tx_len == 0) { 65 63 /* If the queue is empty, allocate a new buffer. */ 66 64 jd->tx_len = len; 67 jd->txq = g_memdup( buf, len);68 65 jd->txq = g_memdup(buf, len); 66 69 67 /* Try if we can write it immediately so we don't have to do 70 68 it via the event handler. If not, add the handler. (In 71 69 most cases it probably won't be necessary.) */ 72 if( ( ret = jabber_write_queue( ic ) ) && jd->tx_len > 0 ) 73 jd->w_inpa = b_input_add( jd->fd, B_EV_IO_WRITE, jabber_write_callback, ic ); 74 } 75 else 76 { 70 if ((ret = jabber_write_queue(ic)) && jd->tx_len > 0) { 71 jd->w_inpa = b_input_add(jd->fd, B_EV_IO_WRITE, jabber_write_callback, ic); 72 } 73 } else { 77 74 /* Just add it to the buffer if it's already filled. The 78 75 event handler is already set. */ 79 jd->txq = g_renew( char, jd->txq, jd->tx_len + len);80 memcpy( jd->txq + jd->tx_len, buf, len);76 jd->txq = g_renew(char, jd->txq, jd->tx_len + len); 77 memcpy(jd->txq + jd->tx_len, buf, len); 81 78 jd->tx_len += len; 82 79 83 80 /* The return value for write() doesn't necessarily mean 84 81 that everything got sent, it mainly means that the … … 87 84 ret = TRUE; 88 85 } 89 86 90 87 return ret; 91 88 } … … 94 91 to use in the function above to escape from having to wait for the event 95 92 handler to call us, if possible. 96 93 97 94 Two different functions are necessary because of the return values: The 98 95 callback should only return TRUE if the write was successful AND if the 99 96 buffer is not empty yet (ie. if the handler has to be called again when 100 97 the socket is ready for more data). */ 101 static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition cond)102 { 103 struct jabber_data *jd = ((struct im_connection *) data)->proto_data;104 98 static gboolean jabber_write_callback(gpointer data, gint fd, b_input_condition cond) 99 { 100 struct jabber_data *jd = ((struct im_connection *) data)->proto_data; 101 105 102 return jd->fd != -1 && 106 jabber_write_queue( data) &&103 jabber_write_queue(data) && 107 104 jd->tx_len > 0; 108 105 } 109 106 110 static gboolean jabber_write_queue( struct im_connection *ic)107 static gboolean jabber_write_queue(struct im_connection *ic) 111 108 { 112 109 struct jabber_data *jd = ic->proto_data; 113 110 int st; 114 115 if ( jd->ssl )116 st = ssl_write( jd->ssl, jd->txq, jd->tx_len);117 else118 st = write( jd->fd, jd->txq, jd->tx_len);119 120 if( st == jd->tx_len ) 121 {111 112 if (jd->ssl) { 113 st = ssl_write(jd->ssl, jd->txq, jd->tx_len); 114 } else { 115 st = write(jd->fd, jd->txq, jd->tx_len); 116 } 117 118 if (st == jd->tx_len) { 122 119 /* We wrote everything, clear the buffer. */ 123 g_free( jd->txq);120 g_free(jd->txq); 124 121 jd->txq = NULL; 125 122 jd->tx_len = 0; 126 123 127 124 return TRUE; 128 } 129 else if( st == 0 || ( st < 0 && !ssl_sockerr_again( jd->ssl ) ) ) 130 { 125 } else if (st == 0 || (st < 0 && !ssl_sockerr_again(jd->ssl))) { 131 126 /* Set fd to -1 to make sure we won't write to it anymore. */ 132 closesocket( jd->fd );/* Shouldn't be necessary after errors? */127 closesocket(jd->fd); /* Shouldn't be necessary after errors? */ 133 128 jd->fd = -1; 134 135 imcb_error( ic, "Short write() to server" ); 136 imc_logout( ic, TRUE ); 137 return FALSE; 138 } 139 else if( st > 0 ) 140 { 129 130 imcb_error(ic, "Short write() to server"); 131 imc_logout(ic, TRUE); 132 return FALSE; 133 } else if (st > 0) { 141 134 char *s; 142 143 s = g_memdup( jd->txq + st, jd->tx_len - st);135 136 s = g_memdup(jd->txq + st, jd->tx_len - st); 144 137 jd->tx_len -= st; 145 g_free( jd->txq);138 g_free(jd->txq); 146 139 jd->txq = s; 147 140 148 141 return TRUE; 149 } 150 else 151 { 142 } else { 152 143 /* Just in case we had EINPROGRESS/EAGAIN: */ 153 144 154 145 return TRUE; 155 146 } 156 147 } 157 148 158 static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition cond)149 static gboolean jabber_read_callback(gpointer data, gint fd, b_input_condition cond) 159 150 { 160 151 struct im_connection *ic = data; … … 162 153 char buf[512]; 163 154 int st; 164 165 if( jd->fd == -1 ) 166 return FALSE; 167 168 if( jd->ssl ) 169 st = ssl_read( jd->ssl, buf, sizeof( buf ) ); 170 else 171 st = read( jd->fd, buf, sizeof( buf ) ); 172 173 if( st > 0 ) 174 { 155 156 if (jd->fd == -1) { 157 return FALSE; 158 } 159 160 if (jd->ssl) { 161 st = ssl_read(jd->ssl, buf, sizeof(buf)); 162 } else { 163 st = read(jd->fd, buf, sizeof(buf)); 164 } 165 166 if (st > 0) { 175 167 /* Parse. */ 176 if( xt_feed( jd->xt, buf, st ) < 0 ) 177 { 178 imcb_error( ic, "XML stream error" ); 179 imc_logout( ic, TRUE ); 168 if (xt_feed(jd->xt, buf, st) < 0) { 169 imcb_error(ic, "XML stream error"); 170 imc_logout(ic, TRUE); 180 171 return FALSE; 181 172 } 182 173 183 174 /* Execute all handlers. */ 184 if( !xt_handle( jd->xt, NULL, 1 ) ) 185 { 175 if (!xt_handle(jd->xt, NULL, 1)) { 186 176 /* Don't do anything, the handlers should have 187 177 aborted the connection already. */ 188 178 return FALSE; 189 179 } 190 191 if( jd->flags & JFLAG_STREAM_RESTART ) 192 { 180 181 if (jd->flags & JFLAG_STREAM_RESTART) { 193 182 jd->flags &= ~JFLAG_STREAM_RESTART; 194 jabber_start_stream( ic);195 } 196 183 jabber_start_stream(ic); 184 } 185 197 186 /* Garbage collection. */ 198 xt_cleanup( jd->xt, NULL, 1);199 187 xt_cleanup(jd->xt, NULL, 1); 188 200 189 /* This is a bit hackish, unfortunately. Although xmltree 201 190 has nifty event handler stuff, it only calls handlers … … 203 192 send an opening <stream:stream> tag, we have to check 204 193 this by hand. :-( */ 205 if( !( jd->flags & JFLAG_STREAM_STARTED ) && jd->xt && jd->xt->root ) 206 { 207 if( g_strcasecmp( jd->xt->root->name, "stream:stream" ) == 0 ) 208 { 194 if (!(jd->flags & JFLAG_STREAM_STARTED) && jd->xt && jd->xt->root) { 195 if (g_strcasecmp(jd->xt->root->name, "stream:stream") == 0) { 209 196 jd->flags |= JFLAG_STREAM_STARTED; 210 197 211 198 /* If there's no version attribute, assume 212 199 this is an old server that can't do SASL 213 200 authentication. */ 214 if( !set_getbool( &ic->acc->set, "sasl") || !sasl_supported( ic ) ) 215 { 201 if (!set_getbool(&ic->acc->set, "sasl") || !sasl_supported(ic)) { 216 202 /* If there's no version= tag, we suppose 217 203 this server does NOT implement: XMPP 1.0, 218 204 SASL and TLS. */ 219 if( set_getbool( &ic->acc->set, "tls" ) ) 220 { 221 imcb_error( ic, "TLS is turned on for this " 222 "account, but is not supported by this server" ); 223 imc_logout( ic, FALSE ); 205 if (set_getbool(&ic->acc->set, "tls")) { 206 imcb_error(ic, "TLS is turned on for this " 207 "account, but is not supported by this server"); 208 imc_logout(ic, FALSE); 224 209 return FALSE; 225 } 226 else 227 { 228 return jabber_init_iq_auth( ic ); 210 } else { 211 return jabber_init_iq_auth(ic); 229 212 } 230 213 } 231 } 232 else 233 { 234 imcb_error( ic, "XML stream error" ); 235 imc_logout( ic, TRUE ); 214 } else { 215 imcb_error(ic, "XML stream error"); 216 imc_logout(ic, TRUE); 236 217 return FALSE; 237 218 } 238 219 } 239 } 240 else if( st == 0 || ( st < 0 && !ssl_sockerr_again( jd->ssl ) ) ) 241 { 242 closesocket( jd->fd ); 220 } else if (st == 0 || (st < 0 && !ssl_sockerr_again(jd->ssl))) { 221 closesocket(jd->fd); 243 222 jd->fd = -1; 244 245 imcb_error( ic, "Error while reading from server");246 imc_logout( ic, TRUE);247 return FALSE; 248 } 249 250 if ( ssl_pending( jd->ssl ) )223 224 imcb_error(ic, "Error while reading from server"); 225 imc_logout(ic, TRUE); 226 return FALSE; 227 } 228 229 if (ssl_pending(jd->ssl)) { 251 230 /* OpenSSL empties the TCP buffers completely but may keep some 252 231 data in its internap buffers. select() won't see that, but 253 232 ssl_pending() does. */ 254 return jabber_read_callback( data, fd, cond);255 else233 return jabber_read_callback(data, fd, cond); 234 } else { 256 235 return TRUE; 257 } 258 259 gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ) 260 { 261 struct im_connection *ic = data; 262 263 if( g_slist_find( jabber_connections, ic ) == NULL ) 264 return FALSE; 265 266 if( source == -1 ) 267 { 268 imcb_error( ic, "Could not connect to server" ); 269 imc_logout( ic, TRUE ); 270 return FALSE; 271 } 272 273 imcb_log( ic, "Connected to server, logging in" ); 274 275 return jabber_start_stream( ic ); 276 } 277 278 gboolean jabber_connected_ssl( gpointer data, int returncode, void *source, b_input_condition cond ) 236 } 237 } 238 239 gboolean jabber_connected_plain(gpointer data, gint source, b_input_condition cond) 240 { 241 struct im_connection *ic = data; 242 243 if (g_slist_find(jabber_connections, ic) == NULL) { 244 return FALSE; 245 } 246 247 if (source == -1) { 248 imcb_error(ic, "Could not connect to server"); 249 imc_logout(ic, TRUE); 250 return FALSE; 251 } 252 253 imcb_log(ic, "Connected to server, logging in"); 254 255 return jabber_start_stream(ic); 256 } 257 258 gboolean jabber_connected_ssl(gpointer data, int returncode, void *source, b_input_condition cond) 279 259 { 280 260 struct im_connection *ic = data; 281 261 struct jabber_data *jd; 282 283 if( g_slist_find( jabber_connections, ic ) == NULL ) 284 return FALSE; 285 262 263 if (g_slist_find(jabber_connections, ic) == NULL) { 264 return FALSE; 265 } 266 286 267 jd = ic->proto_data; 287 288 if( source == NULL ) 289 { 268 269 if (source == NULL) { 290 270 /* The SSL connection will be cleaned up by the SSL lib 291 271 already, set it to NULL here to prevent a double cleanup: */ 292 272 jd->ssl = NULL; 293 294 if( returncode != 0 ) 295 { 296 char *err = ssl_verify_strerror( returncode ); 297 imcb_error( ic, "Certificate verification problem 0x%x: %s", 298 returncode, err ? err : "Unknown" ); 299 g_free( err ); 300 imc_logout( ic, FALSE ); 301 } 302 else 303 { 304 imcb_error( ic, "Could not connect to server" ); 305 imc_logout( ic, TRUE ); 306 } 307 308 return FALSE; 309 } 310 311 imcb_log( ic, "Connected to server, logging in" ); 312 313 return jabber_start_stream( ic ); 314 } 315 316 static xt_status jabber_end_of_stream( struct xt_node *node, gpointer data ) 317 { 318 imc_logout( data, TRUE ); 273 274 if (returncode != 0) { 275 char *err = ssl_verify_strerror(returncode); 276 imcb_error(ic, "Certificate verification problem 0x%x: %s", 277 returncode, err ? err : "Unknown"); 278 g_free(err); 279 imc_logout(ic, FALSE); 280 } else { 281 imcb_error(ic, "Could not connect to server"); 282 imc_logout(ic, TRUE); 283 } 284 285 return FALSE; 286 } 287 288 imcb_log(ic, "Connected to server, logging in"); 289 290 return jabber_start_stream(ic); 291 } 292 293 static xt_status jabber_end_of_stream(struct xt_node *node, gpointer data) 294 { 295 imc_logout(data, TRUE); 319 296 return XT_ABORT; 320 297 } 321 298 322 static xt_status jabber_pkt_features( struct xt_node *node, gpointer data)299 static xt_status jabber_pkt_features(struct xt_node *node, gpointer data) 323 300 { 324 301 struct im_connection *ic = data; … … 326 303 struct xt_node *c, *reply; 327 304 int trytls; 328 329 trytls = g_strcasecmp( set_getstr( &ic->acc->set, "tls" ), "try" ) == 0; 330 c = xt_find_node( node->children, "starttls" ); 331 if( c && !jd->ssl ) 332 { 305 306 trytls = g_strcasecmp(set_getstr(&ic->acc->set, "tls"), "try") == 0; 307 c = xt_find_node(node->children, "starttls"); 308 if (c && !jd->ssl) { 333 309 /* If the server advertises the STARTTLS feature and if we're 334 310 not in a secure connection already: */ 335 336 c = xt_find_node( c->children, "required" ); 337 338 if( c && ( !trytls && !set_getbool( &ic->acc->set, "tls" ) ) ) 339 { 340 imcb_error( ic, "Server requires TLS connections, but TLS is turned off for this account" ); 341 imc_logout( ic, FALSE ); 342 311 312 c = xt_find_node(c->children, "required"); 313 314 if (c && (!trytls && !set_getbool(&ic->acc->set, "tls"))) { 315 imcb_error(ic, "Server requires TLS connections, but TLS is turned off for this account"); 316 imc_logout(ic, FALSE); 317 343 318 return XT_ABORT; 344 319 } 345 320 346 321 /* Only run this if the tls setting is set to true or try: */ 347 if( ( trytls || set_getbool( &ic->acc->set, "tls" ) ) ) 348 { 349 reply = xt_new_node( "starttls", NULL, NULL ); 350 xt_add_attr( reply, "xmlns", XMLNS_TLS ); 351 if( !jabber_write_packet( ic, reply ) ) 352 { 353 xt_free_node( reply ); 322 if ((trytls || set_getbool(&ic->acc->set, "tls"))) { 323 reply = xt_new_node("starttls", NULL, NULL); 324 xt_add_attr(reply, "xmlns", XMLNS_TLS); 325 if (!jabber_write_packet(ic, reply)) { 326 xt_free_node(reply); 354 327 return XT_ABORT; 355 328 } 356 xt_free_node( reply);357 329 xt_free_node(reply); 330 358 331 return XT_HANDLED; 359 332 } 360 } 361 else if( !c && !jd->ssl ) 362 { 333 } else if (!c && !jd->ssl) { 363 334 /* If the server does not advertise the STARTTLS feature and 364 335 we're not in a secure connection already: (Servers have a 365 336 habit of not advertising <starttls/> anymore when already 366 337 using SSL/TLS. */ 367 368 if( !trytls && set_getbool( &ic->acc->set, "tls" ) ) 369 { 370 imcb_error( ic, "TLS is turned on for this account, but is not supported by this server" ); 371 imc_logout( ic, FALSE ); 372 338 339 if (!trytls && set_getbool(&ic->acc->set, "tls")) { 340 imcb_error(ic, "TLS is turned on for this account, but is not supported by this server"); 341 imc_logout(ic, FALSE); 342 373 343 return XT_ABORT; 374 344 } 375 345 } 376 346 377 347 /* This one used to be in jabber_handlers[], but it has to be done 378 348 from here to make sure the TLS session will be initialized 379 349 properly before we attempt SASL authentication. */ 380 if( ( c = xt_find_node( node->children, "mechanisms" ) ) ) 381 { 382 if( sasl_pkt_mechanisms( c, data ) == XT_ABORT ) 350 if ((c = xt_find_node(node->children, "mechanisms"))) { 351 if (sasl_pkt_mechanisms(c, data) == XT_ABORT) { 383 352 return XT_ABORT; 353 } 384 354 } 385 355 /* If the server *SEEMS* to support SASL authentication but doesn't … … 387 357 other way. jabber.com doesn't seem to do SASL while it pretends 388 358 to be XMPP 1.0 compliant! */ 389 else if( !( jd->flags & JFLAG_AUTHENTICATED ) && set_getbool( &ic->acc->set, "sasl") && sasl_supported( ic ) ) 390 { 391 if( !jabber_init_iq_auth( ic ) ) 359 else if (!(jd->flags & JFLAG_AUTHENTICATED) && set_getbool(&ic->acc->set, "sasl") && sasl_supported(ic)) { 360 if (!jabber_init_iq_auth(ic)) { 392 361 return XT_ABORT; 393 } 394 395 if( ( c = xt_find_node( node->children, "bind" ) ) ) 362 } 363 } 364 365 if ((c = xt_find_node(node->children, "bind"))) { 396 366 jd->flags |= JFLAG_WANT_BIND; 397 398 if( ( c = xt_find_node( node->children, "session" ) ) ) 367 } 368 369 if ((c = xt_find_node(node->children, "session"))) { 399 370 jd->flags |= JFLAG_WANT_SESSION; 400 401 if( jd->flags & JFLAG_AUTHENTICATED ) 402 return jabber_pkt_bind_sess( ic, NULL, NULL ); 403 371 } 372 373 if (jd->flags & JFLAG_AUTHENTICATED) { 374 return jabber_pkt_bind_sess(ic, NULL, NULL); 375 } 376 404 377 return XT_HANDLED; 405 378 } 406 379 407 static xt_status jabber_pkt_proceed_tls( struct xt_node *node, gpointer data)380 static xt_status jabber_pkt_proceed_tls(struct xt_node *node, gpointer data) 408 381 { 409 382 struct im_connection *ic = data; 410 383 struct jabber_data *jd = ic->proto_data; 411 384 char *xmlns, *tlsname; 412 413 xmlns = xt_find_attr( node, "xmlns");414 385 386 xmlns = xt_find_attr(node, "xmlns"); 387 415 388 /* Just ignore it when it doesn't seem to be TLS-related (is that at 416 389 all possible??). */ 417 if ( !xmlns || strcmp( xmlns, XMLNS_TLS ) != 0 )390 if (!xmlns || strcmp(xmlns, XMLNS_TLS) != 0) { 418 391 return XT_HANDLED; 419 392 } 393 420 394 /* We don't want event handlers to touch our TLS session while it's 421 395 still initializing! */ 422 b_event_remove( jd->r_inpa ); 423 if( jd->tx_len > 0 ) 424 { 396 b_event_remove(jd->r_inpa); 397 if (jd->tx_len > 0) { 425 398 /* Actually the write queue should be empty here, but just 426 399 to be sure... */ 427 b_event_remove( jd->w_inpa);428 g_free( jd->txq);400 b_event_remove(jd->w_inpa); 401 g_free(jd->txq); 429 402 jd->txq = NULL; 430 403 jd->tx_len = 0; 431 404 } 432 405 jd->w_inpa = jd->r_inpa = 0; 433 434 imcb_log( ic, "Converting stream to TLS");435 406 407 imcb_log(ic, "Converting stream to TLS"); 408 436 409 jd->flags |= JFLAG_STARTTLS_DONE; 437 410 438 /* If the user specified a server for the account, use this server as the 439 * hostname in the certificate verification. Else we use the domain from 411 /* If the user specified a server for the account, use this server as the 412 * hostname in the certificate verification. Else we use the domain from 440 413 * the username. */ 441 if ( ic->acc->server && *ic->acc->server )414 if (ic->acc->server && *ic->acc->server) { 442 415 tlsname = ic->acc->server; 443 else416 } else { 444 417 tlsname = jd->server; 445 446 jd->ssl = ssl_starttls( jd->fd, tlsname, set_getbool( &ic->acc->set, "tls_verify" ), 447 jabber_connected_ssl, ic ); 448 418 } 419 420 jd->ssl = ssl_starttls(jd->fd, tlsname, set_getbool(&ic->acc->set, "tls_verify"), 421 jabber_connected_ssl, ic); 422 449 423 return XT_HANDLED; 450 424 } 451 425 452 static xt_status jabber_pkt_stream_error( struct xt_node *node, gpointer data)426 static xt_status jabber_pkt_stream_error(struct xt_node *node, gpointer data) 453 427 { 454 428 struct im_connection *ic = data; … … 457 431 struct jabber_error *err; 458 432 struct xt_node *host; 459 460 if( !( ic->flags & OPT_LOGGED_IN ) && 461 ( host = xt_find_node( node->children, "see-other-host" ) ) && 462 host->text ) 463 { 433 434 if (!(ic->flags & OPT_LOGGED_IN) && 435 (host = xt_find_node(node->children, "see-other-host")) && 436 host->text) { 464 437 char *s; 465 int port = set_getint( &ic->acc->set, "port");466 438 int port = set_getint(&ic->acc->set, "port"); 439 467 440 /* Let's try to obey this request, if we're not logged 468 441 in yet (i.e. not have too much state yet). */ 469 if( jd->ssl ) 470 ssl_disconnect( jd->ssl ); 471 closesocket( jd->fd ); 472 b_event_remove( jd->r_inpa ); 473 b_event_remove( jd->w_inpa ); 474 442 if (jd->ssl) { 443 ssl_disconnect(jd->ssl); 444 } 445 closesocket(jd->fd); 446 b_event_remove(jd->r_inpa); 447 b_event_remove(jd->w_inpa); 448 475 449 jd->ssl = NULL; 476 450 jd->r_inpa = jd->w_inpa = 0; 477 451 jd->flags &= JFLAG_XMLCONSOLE; 478 479 s = strchr( host->text, ':' ); 480 if( s != NULL ) 481 sscanf( s + 1, "%d", &port ); 482 483 imcb_log( ic, "Redirected to %s", host->text ); 484 jd->fd = proxy_connect( host->text, port, jabber_connected_plain, ic ); 485 452 453 s = strchr(host->text, ':'); 454 if (s != NULL) { 455 sscanf(s + 1, "%d", &port); 456 } 457 458 imcb_log(ic, "Redirected to %s", host->text); 459 jd->fd = proxy_connect(host->text, port, jabber_connected_plain, ic); 460 486 461 return XT_ABORT; 487 462 } 488 489 err = jabber_error_parse( node, XMLNS_STREAM_ERROR);490 463 464 err = jabber_error_parse(node, XMLNS_STREAM_ERROR); 465 491 466 /* Tssk... */ 492 if( err->code == NULL ) 493 { 494 imcb_error( ic, "Unknown stream error reported by server" ); 495 imc_logout( ic, allow_reconnect ); 496 jabber_error_free( err ); 467 if (err->code == NULL) { 468 imcb_error(ic, "Unknown stream error reported by server"); 469 imc_logout(ic, allow_reconnect); 470 jabber_error_free(err); 497 471 return XT_ABORT; 498 472 } 499 473 500 474 /* We know that this is a fatal error. If it's a "conflict" error, we 501 475 should turn off auto-reconnect to make sure we won't get some nasty 502 476 infinite loop! */ 503 if( strcmp( err->code, "conflict" ) == 0 ) 504 { 505 imcb_error( ic, "Account and resource used from a different location" ); 477 if (strcmp(err->code, "conflict") == 0) { 478 imcb_error(ic, "Account and resource used from a different location"); 506 479 allow_reconnect = FALSE; 507 } 508 else if( strcmp( err->code, "not-authorized" ) == 0 ) 509 { 510 imcb_error( ic, "Not authorized" ); 480 } else if (strcmp(err->code, "not-authorized") == 0) { 481 imcb_error(ic, "Not authorized"); 511 482 allow_reconnect = FALSE; 512 } 513 else 514 { 515 imcb_error( ic, "Stream error: %s%s%s", err->code, err->text ? ": " : "", 516 err->text ? err->text : "" ); 517 } 518 519 jabber_error_free( err ); 520 imc_logout( ic, allow_reconnect ); 521 483 } else { 484 imcb_error(ic, "Stream error: %s%s%s", err->code, err->text ? ": " : "", 485 err->text ? err->text : ""); 486 } 487 488 jabber_error_free(err); 489 imc_logout(ic, allow_reconnect); 490 522 491 return XT_ABORT; 523 492 } 524 493 525 static xt_status jabber_xmlconsole( struct xt_node *node, gpointer data ) 526 { 527 struct im_connection *ic = data; 528 struct jabber_data *jd = ic->proto_data; 529 530 if( jd->flags & JFLAG_XMLCONSOLE ) 531 { 494 static xt_status jabber_xmlconsole(struct xt_node *node, gpointer data) 495 { 496 struct im_connection *ic = data; 497 struct jabber_data *jd = ic->proto_data; 498 499 if (jd->flags & JFLAG_XMLCONSOLE) { 532 500 char *msg, *pkt; 533 534 pkt = xt_to_string( node);535 msg = g_strdup_printf( "RX: %s", pkt);536 imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0);537 g_free( msg);538 g_free( pkt);539 } 540 501 502 pkt = xt_to_string(node); 503 msg = g_strdup_printf("RX: %s", pkt); 504 imcb_buddy_msg(ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0); 505 g_free(msg); 506 g_free(pkt); 507 } 508 541 509 return XT_NEXT; 542 510 } … … 557 525 }; 558 526 559 gboolean jabber_start_stream( struct im_connection *ic)527 gboolean jabber_start_stream(struct im_connection *ic) 560 528 { 561 529 struct jabber_data *jd = ic->proto_data; 562 530 int st; 563 531 char *greet; 564 532 565 533 /* We'll start our stream now, so prepare everything to receive one 566 534 from the server too. */ 567 xt_free( jd->xt ); /* In case we're RE-starting. */ 568 jd->xt = xt_new( jabber_handlers, ic ); 569 570 if( jd->r_inpa <= 0 ) 571 jd->r_inpa = b_input_add( jd->fd, B_EV_IO_READ, jabber_read_callback, ic ); 572 573 greet = g_strdup_printf( "%s<stream:stream to=\"%s\" xmlns=\"jabber:client\" " 574 "xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", 575 ( jd->flags & JFLAG_STARTTLS_DONE ) ? "" : "<?xml version='1.0' ?>", 576 jd->server ); 577 578 st = jabber_write( ic, greet, strlen( greet ) ); 579 580 g_free( greet ); 581 535 xt_free(jd->xt); /* In case we're RE-starting. */ 536 jd->xt = xt_new(jabber_handlers, ic); 537 538 if (jd->r_inpa <= 0) { 539 jd->r_inpa = b_input_add(jd->fd, B_EV_IO_READ, jabber_read_callback, ic); 540 } 541 542 greet = g_strdup_printf("%s<stream:stream to=\"%s\" xmlns=\"jabber:client\" " 543 "xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", 544 (jd->flags & JFLAG_STARTTLS_DONE) ? "" : "<?xml version='1.0' ?>", 545 jd->server); 546 547 st = jabber_write(ic, greet, strlen(greet)); 548 549 g_free(greet); 550 582 551 return st; 583 552 } 584 553 585 void jabber_end_stream( struct im_connection *ic)586 { 587 struct jabber_data *jd = ic->proto_data; 588 554 void jabber_end_stream(struct im_connection *ic) 555 { 556 struct jabber_data *jd = ic->proto_data; 557 589 558 /* Let's only do this if the queue is currently empty, otherwise it'd 590 559 take too long anyway. */ 591 if( jd->tx_len == 0 ) 592 { 560 if (jd->tx_len == 0) { 593 561 char eos[] = "</stream:stream>"; 594 562 struct xt_node *node; 595 563 int st = 1; 596 597 if ( ic->flags & OPT_LOGGED_IN )598 {599 node = jabber_make_packet( "presence", "unavailable", NULL, NULL);600 st = jabber_write_packet( ic, node);601 xt_free_node( node );602 } 603 604 if( st )605 jabber_write( ic, eos, strlen( eos ) );606 } 607 } 564 565 if (ic->flags & OPT_LOGGED_IN) { 566 node = jabber_make_packet("presence", "unavailable", NULL, NULL); 567 st = jabber_write_packet(ic, node); 568 xt_free_node(node); 569 } 570 571 if (st) { 572 jabber_write(ic, eos, strlen(eos)); 573 } 574 } 575 } -
protocols/jabber/iq.c
raf359b4 r5ebff60 25 25 #include "sha1.h" 26 26 27 static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig);28 static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig);29 static int jabber_iq_disco_server( struct im_connection *ic);30 31 xt_status jabber_pkt_iq( struct xt_node *node, gpointer data)27 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 28 static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 29 static int jabber_iq_disco_server(struct im_connection *ic); 30 31 xt_status jabber_pkt_iq(struct xt_node *node, gpointer data) 32 32 { 33 33 struct im_connection *ic = data; … … 36 36 char *type, *s; 37 37 int st, pack = 1; 38 39 type = xt_find_attr( node, "type" ); 40 41 if( !type ) 42 { 43 imcb_error( ic, "Received IQ packet without type." ); 44 imc_logout( ic, TRUE ); 38 39 type = xt_find_attr(node, "type"); 40 41 if (!type) { 42 imcb_error(ic, "Received IQ packet without type."); 43 imc_logout(ic, TRUE); 45 44 return XT_ABORT; 46 45 } 47 48 if( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 ) 49 { 50 return jabber_cache_handle_packet( ic, node ); 51 } 52 else if( strcmp( type, "get" ) == 0 ) 53 { 54 if( !( ( c = xt_find_node( node->children, "query" ) ) || 55 ( c = xt_find_node( node->children, "ping" ) ) || 56 ( c = xt_find_node( node->children, "time" ) ) ) || 57 !( s = xt_find_attr( c, "xmlns" ) ) ) 58 { 46 47 if (strcmp(type, "result") == 0 || strcmp(type, "error") == 0) { 48 return jabber_cache_handle_packet(ic, node); 49 } else if (strcmp(type, "get") == 0) { 50 if (!((c = xt_find_node(node->children, "query")) || 51 (c = xt_find_node(node->children, "ping")) || 52 (c = xt_find_node(node->children, "time"))) || 53 !(s = xt_find_attr(c, "xmlns"))) { 59 54 /* Sigh. Who decided to suddenly invent new elements 60 55 instead of just sticking with <query/>? */ 61 56 return XT_HANDLED; 62 57 } 63 64 reply = xt_new_node( "query", NULL, NULL);65 xt_add_attr( reply, "xmlns", s);66 58 59 reply = xt_new_node("query", NULL, NULL); 60 xt_add_attr(reply, "xmlns", s); 61 67 62 /* Of course this is a very essential query to support. ;-) */ 68 if( strcmp( s, XMLNS_VERSION ) == 0 ) 69 { 70 xt_add_child( reply, xt_new_node( "name", set_getstr( &ic->acc->set, "user_agent" ), NULL ) ); 71 xt_add_child( reply, xt_new_node( "version", BITLBEE_VERSION, NULL ) ); 72 xt_add_child( reply, xt_new_node( "os", ARCH, NULL ) ); 73 } 74 else if( strcmp( s, XMLNS_TIME_OLD ) == 0 ) 75 { 63 if (strcmp(s, XMLNS_VERSION) == 0) { 64 xt_add_child(reply, xt_new_node("name", set_getstr(&ic->acc->set, "user_agent"), NULL)); 65 xt_add_child(reply, xt_new_node("version", BITLBEE_VERSION, NULL)); 66 xt_add_child(reply, xt_new_node("os", ARCH, NULL)); 67 } else if (strcmp(s, XMLNS_TIME_OLD) == 0) { 76 68 time_t time_ep; 77 69 char buf[1024]; 78 79 buf[sizeof(buf)-1] = 0; 80 time_ep = time( NULL ); 81 82 strftime( buf, sizeof( buf ) - 1, "%Y%m%dT%H:%M:%S", gmtime( &time_ep ) ); 83 xt_add_child( reply, xt_new_node( "utc", buf, NULL ) ); 84 85 strftime( buf, sizeof( buf ) - 1, "%Z", localtime( &time_ep ) ); 86 xt_add_child( reply, xt_new_node( "tz", buf, NULL ) ); 87 } 88 else if( strcmp( s, XMLNS_TIME ) == 0 ) 89 { 70 71 buf[sizeof(buf) - 1] = 0; 72 time_ep = time(NULL); 73 74 strftime(buf, sizeof(buf) - 1, "%Y%m%dT%H:%M:%S", gmtime(&time_ep)); 75 xt_add_child(reply, xt_new_node("utc", buf, NULL)); 76 77 strftime(buf, sizeof(buf) - 1, "%Z", localtime(&time_ep)); 78 xt_add_child(reply, xt_new_node("tz", buf, NULL)); 79 } else if (strcmp(s, XMLNS_TIME) == 0) { 90 80 time_t time_ep; 91 81 char buf[1024]; 92 93 buf[sizeof(buf)-1] = 0; 94 time_ep = time( NULL ); 95 96 xt_free_node( reply ); 97 reply = xt_new_node( "time", NULL, NULL ); 98 xt_add_attr( reply, "xmlns", XMLNS_TIME ); 99 100 strftime( buf, sizeof( buf ) - 1, "%Y%m%dT%H:%M:%SZ", gmtime( &time_ep ) ); 101 xt_add_child( reply, xt_new_node( "utc", buf, NULL ) ); 102 103 strftime( buf, sizeof( buf ) - 1, "%z", localtime( &time_ep ) ); 104 if( strlen( buf ) >= 5 ) 105 { 82 83 buf[sizeof(buf) - 1] = 0; 84 time_ep = time(NULL); 85 86 xt_free_node(reply); 87 reply = xt_new_node("time", NULL, NULL); 88 xt_add_attr(reply, "xmlns", XMLNS_TIME); 89 90 strftime(buf, sizeof(buf) - 1, "%Y%m%dT%H:%M:%SZ", gmtime(&time_ep)); 91 xt_add_child(reply, xt_new_node("utc", buf, NULL)); 92 93 strftime(buf, sizeof(buf) - 1, "%z", localtime(&time_ep)); 94 if (strlen(buf) >= 5) { 106 95 buf[6] = '\0'; 107 96 buf[5] = buf[4]; … … 109 98 buf[3] = ':'; 110 99 } 111 xt_add_child( reply, xt_new_node( "tzo", buf, NULL ) ); 112 } 113 else if( strcmp( s, XMLNS_PING ) == 0 ) 114 { 115 xt_free_node( reply ); 116 reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), NULL ); 117 if( ( s = xt_find_attr( node, "id" ) ) ) 118 xt_add_attr( reply, "id", s ); 100 xt_add_child(reply, xt_new_node("tzo", buf, NULL)); 101 } else if (strcmp(s, XMLNS_PING) == 0) { 102 xt_free_node(reply); 103 reply = jabber_make_packet("iq", "result", xt_find_attr(node, "from"), NULL); 104 if ((s = xt_find_attr(node, "id"))) { 105 xt_add_attr(reply, "id", s); 106 } 119 107 pack = 0; 120 } 121 else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 ) 122 { 108 } else if (strcmp(s, XMLNS_DISCO_INFO) == 0) { 123 109 const char *features[] = { XMLNS_DISCO_INFO, 124 125 126 127 128 129 130 131 132 133 134 110 XMLNS_VERSION, 111 XMLNS_TIME_OLD, 112 XMLNS_TIME, 113 XMLNS_CHATSTATES, 114 XMLNS_MUC, 115 XMLNS_PING, 116 XMLNS_RECEIPTS, 117 XMLNS_SI, 118 XMLNS_BYTESTREAMS, 119 XMLNS_FILETRANSFER, 120 NULL }; 135 121 const char **f; 136 137 c = xt_new_node( "identity", NULL, NULL ); 138 xt_add_attr( c, "category", "client" ); 139 xt_add_attr( c, "type", "pc" ); 140 xt_add_attr( c, "name", set_getstr( &ic->acc->set, "user_agent" ) ); 141 xt_add_child( reply, c ); 142 143 for( f = features; *f; f ++ ) 144 { 145 c = xt_new_node( "feature", NULL, NULL ); 146 xt_add_attr( c, "var", *f ); 147 xt_add_child( reply, c ); 148 } 149 } 150 else 151 { 152 xt_free_node( reply ); 153 reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL ); 122 123 c = xt_new_node("identity", NULL, NULL); 124 xt_add_attr(c, "category", "client"); 125 xt_add_attr(c, "type", "pc"); 126 xt_add_attr(c, "name", set_getstr(&ic->acc->set, "user_agent")); 127 xt_add_child(reply, c); 128 129 for (f = features; *f; f++) { 130 c = xt_new_node("feature", NULL, NULL); 131 xt_add_attr(c, "var", *f); 132 xt_add_child(reply, c); 133 } 134 } else { 135 xt_free_node(reply); 136 reply = jabber_make_error_packet(node, "feature-not-implemented", "cancel", NULL); 154 137 pack = 0; 155 138 } 156 } 157 else if( strcmp( type, "set" ) == 0 ) 158 { 159 if( ( c = xt_find_node( node->children, "si" ) ) && 160 ( s = xt_find_attr( c, "xmlns" ) ) && 161 ( strcmp( s, XMLNS_SI ) == 0 ) ) 162 { 163 return jabber_si_handle_request( ic, node, c ); 164 } 165 else if( !( c = xt_find_node( node->children, "query" ) ) || 166 !( s = xt_find_attr( c, "xmlns" ) ) ) 167 { 139 } else if (strcmp(type, "set") == 0) { 140 if ((c = xt_find_node(node->children, "si")) && 141 (s = xt_find_attr(c, "xmlns")) && 142 (strcmp(s, XMLNS_SI) == 0)) { 143 return jabber_si_handle_request(ic, node, c); 144 } else if (!(c = xt_find_node(node->children, "query")) || 145 !(s = xt_find_attr(c, "xmlns"))) { 168 146 return XT_HANDLED; 169 } 170 else if( strcmp( s, XMLNS_ROSTER ) == 0 ) 171 { 172 /* This is a roster push. XMPP servers send this when someone 173 was added to (or removed from) the buddy list. AFAIK they're 174 sent even if we added this buddy in our own session. */ 175 int bare_len = strlen( jd->me ); 176 177 if( ( s = xt_find_attr( node, "from" ) ) == NULL || 178 ( strncmp( s, jd->me, bare_len ) == 0 && 179 ( s[bare_len] == 0 || s[bare_len] == '/' ) ) ) 180 { 181 jabber_parse_roster( ic, node, NULL ); 182 147 } else if (strcmp(s, XMLNS_ROSTER) == 0) { 148 /* This is a roster push. XMPP servers send this when someone 149 was added to (or removed from) the buddy list. AFAIK they're 150 sent even if we added this buddy in our own session. */ 151 int bare_len = strlen(jd->me); 152 153 if ((s = xt_find_attr(node, "from")) == NULL || 154 (strncmp(s, jd->me, bare_len) == 0 && 155 (s[bare_len] == 0 || s[bare_len] == '/'))) { 156 jabber_parse_roster(ic, node, NULL); 157 183 158 /* Should we generate a reply here? Don't think it's 184 159 very important... */ 185 } 186 else 187 { 188 imcb_log( ic, "Warning: %s tried to fake a roster push!", s ? s : "(unknown)" ); 189 190 xt_free_node( reply ); 191 reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL ); 160 } else { 161 imcb_log(ic, "Warning: %s tried to fake a roster push!", s ? s : "(unknown)"); 162 163 xt_free_node(reply); 164 reply = jabber_make_error_packet(node, "not-allowed", "cancel", NULL); 192 165 pack = 0; 193 166 } 194 } 195 else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 ) 196 { 167 } else if (strcmp(s, XMLNS_BYTESTREAMS) == 0) { 197 168 /* Bytestream Request (stage 2 of file transfer) */ 198 return jabber_bs_recv_request( ic, node, c ); 199 } 200 else 201 { 202 xt_free_node( reply ); 203 reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL ); 169 return jabber_bs_recv_request(ic, node, c); 170 } else { 171 xt_free_node(reply); 172 reply = jabber_make_error_packet(node, "feature-not-implemented", "cancel", NULL); 204 173 pack = 0; 205 174 } 206 175 } 207 176 208 177 /* If we recognized the xmlns and managed to generate a reply, 209 178 finish and send it. */ 210 if( reply ) 211 { 179 if (reply) { 212 180 /* Normally we still have to pack it into an iq-result 213 181 packet, but for errors, for example, we don't. */ 214 if ( pack )215 {216 reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), reply );217 if( ( s = xt_find_attr( node, "id" ) ) )218 xt_add_attr( reply, "id", s );219 } 220 221 st = jabber_write_packet( ic, reply);222 xt_free_node( reply);223 if ( !st )182 if (pack) { 183 reply = jabber_make_packet("iq", "result", xt_find_attr(node, "from"), reply); 184 if ((s = xt_find_attr(node, "id"))) { 185 xt_add_attr(reply, "id", s); 186 } 187 } 188 189 st = jabber_write_packet(ic, reply); 190 xt_free_node(reply); 191 if (!st) { 224 192 return XT_ABORT; 225 } 226 227 return XT_HANDLED; 228 } 229 230 static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); 231 static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); 232 233 int jabber_init_iq_auth( struct im_connection *ic ) 193 } 194 } 195 196 return XT_HANDLED; 197 } 198 199 static xt_status jabber_do_iq_auth(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 200 static xt_status jabber_finish_iq_auth(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 201 202 int jabber_init_iq_auth(struct im_connection *ic) 234 203 { 235 204 struct jabber_data *jd = ic->proto_data; 236 205 struct xt_node *node; 237 206 int st; 238 239 node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ));240 xt_add_attr( node, "xmlns", XMLNS_AUTH);241 node = jabber_make_packet( "iq", "get", NULL, node);242 243 jabber_cache_add( ic, node, jabber_do_iq_auth);244 st = jabber_write_packet( ic, node);245 207 208 node = xt_new_node("query", NULL, xt_new_node("username", jd->username, NULL)); 209 xt_add_attr(node, "xmlns", XMLNS_AUTH); 210 node = jabber_make_packet("iq", "get", NULL, node); 211 212 jabber_cache_add(ic, node, jabber_do_iq_auth); 213 st = jabber_write_packet(ic, node); 214 246 215 return st; 247 216 } 248 217 249 static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig)218 static xt_status jabber_do_iq_auth(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 250 219 { 251 220 struct jabber_data *jd = ic->proto_data; … … 253 222 xt_status st; 254 223 char *s; 255 256 if( !( query = xt_find_node( node->children, "query" ) ) ) 257 { 258 imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" ); 259 imc_logout( ic, FALSE ); 260 return XT_HANDLED; 261 } 262 224 225 if (!(query = xt_find_node(node->children, "query"))) { 226 imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating"); 227 imc_logout(ic, FALSE); 228 return XT_HANDLED; 229 } 230 263 231 /* Time to authenticate ourselves! */ 264 reply = xt_new_node( "query", NULL, NULL ); 265 xt_add_attr( reply, "xmlns", XMLNS_AUTH ); 266 xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) ); 267 xt_add_child( reply, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) ); 268 269 if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) ) 270 { 232 reply = xt_new_node("query", NULL, NULL); 233 xt_add_attr(reply, "xmlns", XMLNS_AUTH); 234 xt_add_child(reply, xt_new_node("username", jd->username, NULL)); 235 xt_add_child(reply, xt_new_node("resource", set_getstr(&ic->acc->set, "resource"), NULL)); 236 237 if (xt_find_node(query->children, "digest") && (s = xt_find_attr(jd->xt->root, "id"))) { 271 238 /* We can do digest authentication, it seems, and of 272 239 course we prefer that. */ … … 275 242 unsigned char hash[20]; 276 243 int i; 277 278 sha1_init( &sha ); 279 sha1_append( &sha, (unsigned char*) s, strlen( s ) ); 280 sha1_append( &sha, (unsigned char*) ic->acc->pass, strlen( ic->acc->pass ) ); 281 sha1_finish( &sha, hash ); 282 283 for( i = 0; i < 20; i ++ ) 284 sprintf( hash_hex + i * 2, "%02x", hash[i] ); 285 286 xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) ); 287 } 288 else if( xt_find_node( query->children, "password" ) ) 289 { 244 245 sha1_init(&sha); 246 sha1_append(&sha, (unsigned char *) s, strlen(s)); 247 sha1_append(&sha, (unsigned char *) ic->acc->pass, strlen(ic->acc->pass)); 248 sha1_finish(&sha, hash); 249 250 for (i = 0; i < 20; i++) { 251 sprintf(hash_hex + i * 2, "%02x", hash[i]); 252 } 253 254 xt_add_child(reply, xt_new_node("digest", hash_hex, NULL)); 255 } else if (xt_find_node(query->children, "password")) { 290 256 /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */ 291 xt_add_child( reply, xt_new_node( "password", ic->acc->pass, NULL ) ); 292 } 293 else 294 { 295 xt_free_node( reply ); 296 297 imcb_error( ic, "Can't find suitable authentication method" ); 298 imc_logout( ic, FALSE ); 257 xt_add_child(reply, xt_new_node("password", ic->acc->pass, NULL)); 258 } else { 259 xt_free_node(reply); 260 261 imcb_error(ic, "Can't find suitable authentication method"); 262 imc_logout(ic, FALSE); 299 263 return XT_ABORT; 300 264 } 301 302 reply = jabber_make_packet( "iq", "set", NULL, reply);303 jabber_cache_add( ic, reply, jabber_finish_iq_auth);304 st = jabber_write_packet( ic, reply);305 265 266 reply = jabber_make_packet("iq", "set", NULL, reply); 267 jabber_cache_add(ic, reply, jabber_finish_iq_auth); 268 st = jabber_write_packet(ic, reply); 269 306 270 return st ? XT_HANDLED : XT_ABORT; 307 271 } 308 272 309 static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig)273 static xt_status jabber_finish_iq_auth(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 310 274 { 311 275 struct jabber_data *jd = ic->proto_data; 312 276 char *type; 313 314 if( !( type = xt_find_attr( node, "type" ) ) ) 315 { 316 imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" ); 317 imc_logout( ic, FALSE ); 318 return XT_HANDLED; 319 } 320 321 if( strcmp( type, "error" ) == 0 ) 322 { 323 imcb_error( ic, "Authentication failure" ); 324 imc_logout( ic, FALSE ); 277 278 if (!(type = xt_find_attr(node, "type"))) { 279 imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating"); 280 imc_logout(ic, FALSE); 281 return XT_HANDLED; 282 } 283 284 if (strcmp(type, "error") == 0) { 285 imcb_error(ic, "Authentication failure"); 286 imc_logout(ic, FALSE); 325 287 return XT_ABORT; 326 } 327 else if( strcmp( type, "result" ) == 0 ) 328 { 288 } else if (strcmp(type, "result") == 0) { 329 289 /* This happens when we just successfully authenticated the 330 290 old (non-SASL) way. */ 331 291 jd->flags |= JFLAG_AUTHENTICATED; 332 if ( !jabber_get_roster( ic ) )292 if (!jabber_get_roster(ic)) { 333 293 return XT_ABORT; 334 if( !jabber_iq_disco_server( ic ) ) 294 } 295 if (!jabber_iq_disco_server(ic)) { 335 296 return XT_ABORT; 336 } 337 338 return XT_HANDLED; 339 } 340 341 xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) 297 } 298 } 299 300 return XT_HANDLED; 301 } 302 303 xt_status jabber_pkt_bind_sess(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 342 304 { 343 305 struct jabber_data *jd = ic->proto_data; 344 306 struct xt_node *c, *reply = NULL; 345 307 char *s; 346 347 if( node && ( c = xt_find_node( node->children, "bind" ) ) ) 348 { 349 c = xt_find_node( c->children, "jid" ); 350 if( !c || !c->text ) 351 { 308 309 if (node && (c = xt_find_node(node->children, "bind"))) { 310 c = xt_find_node(c->children, "jid"); 311 if (!c || !c->text) { 352 312 /* Server is crap, but this is no disaster. */ 353 } 354 else if( jabber_compare_jid( jd->me, c->text ) == 0 ) 355 { 356 s = strchr( c->text, '/' ); 357 if( s ) 313 } else if (jabber_compare_jid(jd->me, c->text) == 0) { 314 s = strchr(c->text, '/'); 315 if (s) { 358 316 *s = '\0'; 359 jabber_set_me( ic, c->text ); 360 if( s ) 317 } 318 jabber_set_me(ic, c->text); 319 if (s) { 361 320 *s = '/'; 362 }363 else if( c && c->text_len && ( s = strchr( c->text, '/' )) &&364 strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 )365 imcb_log( ic, "Server changed session resource string to `%s'", s + 1);366 }367 368 if( jd->flags & JFLAG_WANT_BIND ) 369 {370 reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ));371 xt_add_attr( reply, "xmlns", XMLNS_BIND);321 } 322 } else if (c && c->text_len && (s = strchr(c->text, '/')) && 323 strcmp(s + 1, set_getstr(&ic->acc->set, "resource")) != 0) { 324 imcb_log(ic, "Server changed session resource string to `%s'", s + 1); 325 } 326 } 327 328 if (jd->flags & JFLAG_WANT_BIND) { 329 reply = xt_new_node("bind", NULL, xt_new_node("resource", set_getstr(&ic->acc->set, "resource"), NULL)); 330 xt_add_attr(reply, "xmlns", XMLNS_BIND); 372 331 jd->flags &= ~JFLAG_WANT_BIND; 373 } 374 else if( jd->flags & JFLAG_WANT_SESSION ) 375 { 376 reply = xt_new_node( "session", NULL, NULL ); 377 xt_add_attr( reply, "xmlns", XMLNS_SESSION ); 332 } else if (jd->flags & JFLAG_WANT_SESSION) { 333 reply = xt_new_node("session", NULL, NULL); 334 xt_add_attr(reply, "xmlns", XMLNS_SESSION); 378 335 jd->flags &= ~JFLAG_WANT_SESSION; 379 336 } 380 381 if( reply != NULL ) 382 { 383 reply = jabber_make_packet( "iq", "set", NULL, reply ); 384 jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); 385 386 if( !jabber_write_packet( ic, reply ) ) 337 338 if (reply != NULL) { 339 reply = jabber_make_packet("iq", "set", NULL, reply); 340 jabber_cache_add(ic, reply, jabber_pkt_bind_sess); 341 342 if (!jabber_write_packet(ic, reply)) { 387 343 return XT_ABORT; 388 } 389 else if( ( jd->flags & ( JFLAG_WANT_BIND | JFLAG_WANT_SESSION ) ) == 0 ) 390 { 391 if( !jabber_get_roster( ic ) ) 344 } 345 } else if ((jd->flags & (JFLAG_WANT_BIND | JFLAG_WANT_SESSION)) == 0) { 346 if (!jabber_get_roster(ic)) { 392 347 return XT_ABORT; 393 if( !jabber_iq_disco_server( ic ) ) 348 } 349 if (!jabber_iq_disco_server(ic)) { 394 350 return XT_ABORT; 395 } 396 397 return XT_HANDLED; 398 } 399 400 int jabber_get_roster( struct im_connection *ic ) 351 } 352 } 353 354 return XT_HANDLED; 355 } 356 357 int jabber_get_roster(struct im_connection *ic) 401 358 { 402 359 struct xt_node *node; 403 360 int st; 404 405 imcb_log( ic, "Authenticated, requesting buddy list");406 407 node = xt_new_node( "query", NULL, NULL);408 xt_add_attr( node, "xmlns", XMLNS_ROSTER);409 node = jabber_make_packet( "iq", "get", NULL, node);410 411 jabber_cache_add( ic, node, jabber_parse_roster);412 st = jabber_write_packet( ic, node);413 361 362 imcb_log(ic, "Authenticated, requesting buddy list"); 363 364 node = xt_new_node("query", NULL, NULL); 365 xt_add_attr(node, "xmlns", XMLNS_ROSTER); 366 node = jabber_make_packet("iq", "get", NULL, node); 367 368 jabber_cache_add(ic, node, jabber_parse_roster); 369 st = jabber_write_packet(ic, node); 370 414 371 return st; 415 372 } 416 373 417 static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig)374 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 418 375 { 419 376 struct xt_node *query, *c; 420 int initial = ( orig != NULL ); 421 422 if( !( query = xt_find_node( node->children, "query" ) ) ) 423 { 424 imcb_log( ic, "Warning: Received NULL roster packet" ); 425 return XT_HANDLED; 426 } 427 377 int initial = (orig != NULL); 378 379 if (!(query = xt_find_node(node->children, "query"))) { 380 imcb_log(ic, "Warning: Received NULL roster packet"); 381 return XT_HANDLED; 382 } 383 428 384 c = query->children; 429 while( ( c = xt_find_node( c, "item" ) ) ) 430 { 431 struct xt_node *group = xt_find_node( c->children, "group" ); 432 char *jid = xt_find_attr( c, "jid" ); 433 char *name = xt_find_attr( c, "name" ); 434 char *sub = xt_find_attr( c, "subscription" ); 435 436 if( jid && sub ) 437 { 438 if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) 439 { 440 imcb_add_buddy( ic, jid, ( group && group->text_len ) ? 441 group->text : NULL ); 442 443 if( name ) 444 imcb_rename_buddy( ic, jid, name ); 445 } 446 else if( strcmp( sub, "remove" ) == 0 ) 447 { 448 jabber_buddy_remove_bare( ic, jid ); 449 imcb_remove_buddy( ic, jid, NULL ); 450 } 451 } 452 385 while ((c = xt_find_node(c, "item"))) { 386 struct xt_node *group = xt_find_node(c->children, "group"); 387 char *jid = xt_find_attr(c, "jid"); 388 char *name = xt_find_attr(c, "name"); 389 char *sub = xt_find_attr(c, "subscription"); 390 391 if (jid && sub) { 392 if ((strcmp(sub, "both") == 0 || strcmp(sub, "to") == 0)) { 393 imcb_add_buddy(ic, jid, (group && group->text_len) ? 394 group->text : NULL); 395 396 if (name) { 397 imcb_rename_buddy(ic, jid, name); 398 } 399 } else if (strcmp(sub, "remove") == 0) { 400 jabber_buddy_remove_bare(ic, jid); 401 imcb_remove_buddy(ic, jid, NULL); 402 } 403 } 404 453 405 c = c->next; 454 406 } 455 456 if( initial ) 457 imcb_connected( ic ); 458 459 return XT_HANDLED; 460 } 461 462 int jabber_get_vcard( struct im_connection *ic, char *bare_jid ) 407 408 if (initial) { 409 imcb_connected(ic); 410 } 411 412 return XT_HANDLED; 413 } 414 415 int jabber_get_vcard(struct im_connection *ic, char *bare_jid) 463 416 { 464 417 struct xt_node *node; 465 466 if( strchr( bare_jid, '/' ) ) 467 return 1; /* This was an error, but return 0 should only be done if the connection died... */ 468 469 node = xt_new_node( "vCard", NULL, NULL ); 470 xt_add_attr( node, "xmlns", XMLNS_VCARD ); 471 node = jabber_make_packet( "iq", "get", bare_jid, node ); 472 473 jabber_cache_add( ic, node, jabber_iq_display_vcard ); 474 return jabber_write_packet( ic, node ); 475 } 476 477 static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) 418 419 if (strchr(bare_jid, '/')) { 420 return 1; /* This was an error, but return 0 should only be done if the connection died... */ 421 422 } 423 node = xt_new_node("vCard", NULL, NULL); 424 xt_add_attr(node, "xmlns", XMLNS_VCARD); 425 node = jabber_make_packet("iq", "get", bare_jid, node); 426 427 jabber_cache_add(ic, node, jabber_iq_display_vcard); 428 return jabber_write_packet(ic, node); 429 } 430 431 static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 478 432 { 479 433 struct xt_node *vc, *c, *sc; /* subchild, ic is already in use ;-) */ 480 434 GString *reply; 481 435 char *s; 482 483 if( ( s = xt_find_attr( node, "type" ) ) == NULL || 484 strcmp( s, "result" ) != 0 || 485 ( vc = xt_find_node( node->children, "vCard" ) ) == NULL ) 486 { 487 s = xt_find_attr( orig, "to" ); /* If this returns NULL something's wrong.. */ 488 imcb_log( ic, "Could not retrieve vCard of %s", s ? s : "(NULL)" ); 489 return XT_HANDLED; 490 } 491 492 s = xt_find_attr( orig, "to" ); 493 reply = g_string_new( "vCard information for " ); 494 reply = g_string_append( reply, s ? s : "(NULL)" ); 495 reply = g_string_append( reply, ":\n" ); 496 436 437 if ((s = xt_find_attr(node, "type")) == NULL || 438 strcmp(s, "result") != 0 || 439 (vc = xt_find_node(node->children, "vCard")) == NULL) { 440 s = xt_find_attr(orig, "to"); /* If this returns NULL something's wrong.. */ 441 imcb_log(ic, "Could not retrieve vCard of %s", s ? s : "(NULL)"); 442 return XT_HANDLED; 443 } 444 445 s = xt_find_attr(orig, "to"); 446 reply = g_string_new("vCard information for "); 447 reply = g_string_append(reply, s ? s : "(NULL)"); 448 reply = g_string_append(reply, ":\n"); 449 497 450 /* I hate this format, I really do... */ 498 499 if( ( c = xt_find_node( vc->children, "FN" ) ) && c->text_len ) 500 g_string_append_printf( reply, "Name: %s\n", c->text ); 501 502 if( ( c = xt_find_node( vc->children, "N" ) ) && c->children ) 503 { 504 reply = g_string_append( reply, "Full name:" ); 505 506 if( ( sc = xt_find_node( c->children, "PREFIX" ) ) && sc->text_len ) 507 g_string_append_printf( reply, " %s", sc->text ); 508 if( ( sc = xt_find_node( c->children, "GIVEN" ) ) && sc->text_len ) 509 g_string_append_printf( reply, " %s", sc->text ); 510 if( ( sc = xt_find_node( c->children, "MIDDLE" ) ) && sc->text_len ) 511 g_string_append_printf( reply, " %s", sc->text ); 512 if( ( sc = xt_find_node( c->children, "FAMILY" ) ) && sc->text_len ) 513 g_string_append_printf( reply, " %s", sc->text ); 514 if( ( sc = xt_find_node( c->children, "SUFFIX" ) ) && sc->text_len ) 515 g_string_append_printf( reply, " %s", sc->text ); 516 517 reply = g_string_append_c( reply, '\n' ); 518 } 519 520 if( ( c = xt_find_node( vc->children, "NICKNAME" ) ) && c->text_len ) 521 g_string_append_printf( reply, "Nickname: %s\n", c->text ); 522 523 if( ( c = xt_find_node( vc->children, "BDAY" ) ) && c->text_len ) 524 g_string_append_printf( reply, "Date of birth: %s\n", c->text ); 525 451 452 if ((c = xt_find_node(vc->children, "FN")) && c->text_len) { 453 g_string_append_printf(reply, "Name: %s\n", c->text); 454 } 455 456 if ((c = xt_find_node(vc->children, "N")) && c->children) { 457 reply = g_string_append(reply, "Full name:"); 458 459 if ((sc = xt_find_node(c->children, "PREFIX")) && sc->text_len) { 460 g_string_append_printf(reply, " %s", sc->text); 461 } 462 if ((sc = xt_find_node(c->children, "GIVEN")) && sc->text_len) { 463 g_string_append_printf(reply, " %s", sc->text); 464 } 465 if ((sc = xt_find_node(c->children, "MIDDLE")) && sc->text_len) { 466 g_string_append_printf(reply, " %s", sc->text); 467 } 468 if ((sc = xt_find_node(c->children, "FAMILY")) && sc->text_len) { 469 g_string_append_printf(reply, " %s", sc->text); 470 } 471 if ((sc = xt_find_node(c->children, "SUFFIX")) && sc->text_len) { 472 g_string_append_printf(reply, " %s", sc->text); 473 } 474 475 reply = g_string_append_c(reply, '\n'); 476 } 477 478 if ((c = xt_find_node(vc->children, "NICKNAME")) && c->text_len) { 479 g_string_append_printf(reply, "Nickname: %s\n", c->text); 480 } 481 482 if ((c = xt_find_node(vc->children, "BDAY")) && c->text_len) { 483 g_string_append_printf(reply, "Date of birth: %s\n", c->text); 484 } 485 526 486 /* Slightly alternative use of for... ;-) */ 527 for( c = vc->children; ( c = xt_find_node( c, "EMAIL" ) ); c = c->next ) 528 { 529 if( ( sc = xt_find_node( c->children, "USERID" ) ) == NULL || sc->text_len == 0 ) 487 for (c = vc->children; (c = xt_find_node(c, "EMAIL")); c = c->next) { 488 if ((sc = xt_find_node(c->children, "USERID")) == NULL || sc->text_len == 0) { 530 489 continue; 531 532 if( xt_find_node( c->children, "HOME" ) ) 490 } 491 492 if (xt_find_node(c->children, "HOME")) { 533 493 s = "Home"; 534 else if( xt_find_node( c->children, "WORK" ) )494 } else if (xt_find_node(c->children, "WORK")) { 535 495 s = "Work"; 536 else496 } else { 537 497 s = "Misc."; 538 539 g_string_append_printf( reply, "%s e-mail address: %s\n", s, sc->text ); 540 } 541 542 if( ( c = xt_find_node( vc->children, "URL" ) ) && c->text_len ) 543 g_string_append_printf( reply, "Homepage: %s\n", c->text ); 544 498 } 499 500 g_string_append_printf(reply, "%s e-mail address: %s\n", s, sc->text); 501 } 502 503 if ((c = xt_find_node(vc->children, "URL")) && c->text_len) { 504 g_string_append_printf(reply, "Homepage: %s\n", c->text); 505 } 506 545 507 /* Slightly alternative use of for... ;-) */ 546 for( c = vc->children; ( c = xt_find_node( c, "ADR" ) ); c = c->next ) 547 { 548 if( xt_find_node( c->children, "HOME" ) ) 508 for (c = vc->children; (c = xt_find_node(c, "ADR")); c = c->next) { 509 if (xt_find_node(c->children, "HOME")) { 549 510 s = "Home"; 550 else if( xt_find_node( c->children, "WORK" ) )511 } else if (xt_find_node(c->children, "WORK")) { 551 512 s = "Work"; 552 else513 } else { 553 514 s = "Misc."; 554 555 g_string_append_printf( reply, "%s address: ", s ); 556 557 if( ( sc = xt_find_node( c->children, "STREET" ) ) && sc->text_len ) 558 g_string_append_printf( reply, "%s ", sc->text ); 559 if( ( sc = xt_find_node( c->children, "EXTADR" ) ) && sc->text_len ) 560 g_string_append_printf( reply, "%s, ", sc->text ); 561 if( ( sc = xt_find_node( c->children, "PCODE" ) ) && sc->text_len ) 562 g_string_append_printf( reply, "%s, ", sc->text ); 563 if( ( sc = xt_find_node( c->children, "LOCALITY" ) ) && sc->text_len ) 564 g_string_append_printf( reply, "%s, ", sc->text ); 565 if( ( sc = xt_find_node( c->children, "REGION" ) ) && sc->text_len ) 566 g_string_append_printf( reply, "%s, ", sc->text ); 567 if( ( sc = xt_find_node( c->children, "CTRY" ) ) && sc->text_len ) 568 g_string_append_printf( reply, "%s", sc->text ); 569 570 if( reply->str[reply->len-2] == ',' ) 571 reply = g_string_truncate( reply, reply->len-2 ); 572 573 reply = g_string_append_c( reply, '\n' ); 574 } 575 576 for( c = vc->children; ( c = xt_find_node( c, "TEL" ) ); c = c->next ) 577 { 578 if( ( sc = xt_find_node( c->children, "NUMBER" ) ) == NULL || sc->text_len == 0 ) 515 } 516 517 g_string_append_printf(reply, "%s address: ", s); 518 519 if ((sc = xt_find_node(c->children, "STREET")) && sc->text_len) { 520 g_string_append_printf(reply, "%s ", sc->text); 521 } 522 if ((sc = xt_find_node(c->children, "EXTADR")) && sc->text_len) { 523 g_string_append_printf(reply, "%s, ", sc->text); 524 } 525 if ((sc = xt_find_node(c->children, "PCODE")) && sc->text_len) { 526 g_string_append_printf(reply, "%s, ", sc->text); 527 } 528 if ((sc = xt_find_node(c->children, "LOCALITY")) && sc->text_len) { 529 g_string_append_printf(reply, "%s, ", sc->text); 530 } 531 if ((sc = xt_find_node(c->children, "REGION")) && sc->text_len) { 532 g_string_append_printf(reply, "%s, ", sc->text); 533 } 534 if ((sc = xt_find_node(c->children, "CTRY")) && sc->text_len) { 535 g_string_append_printf(reply, "%s", sc->text); 536 } 537 538 if (reply->str[reply->len - 2] == ',') { 539 reply = g_string_truncate(reply, reply->len - 2); 540 } 541 542 reply = g_string_append_c(reply, '\n'); 543 } 544 545 for (c = vc->children; (c = xt_find_node(c, "TEL")); c = c->next) { 546 if ((sc = xt_find_node(c->children, "NUMBER")) == NULL || sc->text_len == 0) { 579 547 continue; 580 581 if( xt_find_node( c->children, "HOME" ) ) 548 } 549 550 if (xt_find_node(c->children, "HOME")) { 582 551 s = "Home"; 583 else if( xt_find_node( c->children, "WORK" ) )552 } else if (xt_find_node(c->children, "WORK")) { 584 553 s = "Work"; 585 else554 } else { 586 555 s = "Misc."; 587 588 g_string_append_printf( reply, "%s phone number: %s\n", s, sc->text ); 589 } 590 591 if( ( c = xt_find_node( vc->children, "DESC" ) ) && c->text_len ) 592 g_string_append_printf( reply, "Other information:\n%s", c->text ); 593 556 } 557 558 g_string_append_printf(reply, "%s phone number: %s\n", s, sc->text); 559 } 560 561 if ((c = xt_find_node(vc->children, "DESC")) && c->text_len) { 562 g_string_append_printf(reply, "Other information:\n%s", c->text); 563 } 564 594 565 /* *sigh* */ 595 596 imcb_log( ic, "%s", reply->str);597 g_string_free( reply, TRUE);598 599 return XT_HANDLED; 600 } 601 602 static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct xt_node *node, struct xt_node *orig);603 604 int jabber_add_to_roster( struct im_connection *ic, const char *handle, const char *name, const char *group)566 567 imcb_log(ic, "%s", reply->str); 568 g_string_free(reply, TRUE); 569 570 return XT_HANDLED; 571 } 572 573 static xt_status jabber_add_to_roster_callback(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 574 575 int jabber_add_to_roster(struct im_connection *ic, const char *handle, const char *name, const char *group) 605 576 { 606 577 struct xt_node *node; 607 578 int st; 608 579 609 580 /* Build the item entry */ 610 node = xt_new_node( "item", NULL, NULL ); 611 xt_add_attr( node, "jid", handle ); 612 if( name ) 613 xt_add_attr( node, "name", name ); 614 if( group ) 615 xt_add_child( node, xt_new_node( "group", group, NULL ) ); 616 581 node = xt_new_node("item", NULL, NULL); 582 xt_add_attr(node, "jid", handle); 583 if (name) { 584 xt_add_attr(node, "name", name); 585 } 586 if (group) { 587 xt_add_child(node, xt_new_node("group", group, NULL)); 588 } 589 617 590 /* And pack it into a roster-add packet */ 618 node = xt_new_node( "query", NULL, node);619 xt_add_attr( node, "xmlns", XMLNS_ROSTER);620 node = jabber_make_packet( "iq", "set", NULL, node);621 jabber_cache_add( ic, node, jabber_add_to_roster_callback);622 623 st = jabber_write_packet( ic, node);624 591 node = xt_new_node("query", NULL, node); 592 xt_add_attr(node, "xmlns", XMLNS_ROSTER); 593 node = jabber_make_packet("iq", "set", NULL, node); 594 jabber_cache_add(ic, node, jabber_add_to_roster_callback); 595 596 st = jabber_write_packet(ic, node); 597 625 598 return st; 626 599 } 627 600 628 static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct xt_node *node, struct xt_node *orig)601 static xt_status jabber_add_to_roster_callback(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 629 602 { 630 603 char *s, *jid = NULL; 631 604 struct xt_node *c; 632 633 if( ( c = xt_find_node( orig->children, "query" ) ) && 634 ( c = xt_find_node( c->children, "item" ) ) && 635 ( jid = xt_find_attr( c, "jid" ) ) && 636 ( s = xt_find_attr( node, "type" ) ) && 637 strcmp( s, "result" ) == 0 ) 638 { 639 if( bee_user_by_handle( ic->bee, ic, jid ) == NULL ) 640 imcb_add_buddy( ic, jid, NULL ); 641 } 642 else 643 { 644 imcb_log( ic, "Error while adding `%s' to your contact list.", 645 jid ? jid : "(unknown handle)" ); 646 } 647 648 return XT_HANDLED; 649 } 650 651 int jabber_remove_from_roster( struct im_connection *ic, char *handle ) 605 606 if ((c = xt_find_node(orig->children, "query")) && 607 (c = xt_find_node(c->children, "item")) && 608 (jid = xt_find_attr(c, "jid")) && 609 (s = xt_find_attr(node, "type")) && 610 strcmp(s, "result") == 0) { 611 if (bee_user_by_handle(ic->bee, ic, jid) == NULL) { 612 imcb_add_buddy(ic, jid, NULL); 613 } 614 } else { 615 imcb_log(ic, "Error while adding `%s' to your contact list.", 616 jid ? jid : "(unknown handle)"); 617 } 618 619 return XT_HANDLED; 620 } 621 622 int jabber_remove_from_roster(struct im_connection *ic, char *handle) 652 623 { 653 624 struct xt_node *node; 654 625 int st; 655 626 656 627 /* Build the item entry */ 657 node = xt_new_node( "item", NULL, NULL);658 xt_add_attr( node, "jid", handle);659 xt_add_attr( node, "subscription", "remove");660 628 node = xt_new_node("item", NULL, NULL); 629 xt_add_attr(node, "jid", handle); 630 xt_add_attr(node, "subscription", "remove"); 631 661 632 /* And pack it into a roster-add packet */ 662 node = xt_new_node( "query", NULL, node);663 xt_add_attr( node, "xmlns", XMLNS_ROSTER);664 node = jabber_make_packet( "iq", "set", NULL, node);665 666 st = jabber_write_packet( ic, node);667 668 xt_free_node( node);633 node = xt_new_node("query", NULL, node); 634 xt_add_attr(node, "xmlns", XMLNS_ROSTER); 635 node = jabber_make_packet("iq", "set", NULL, node); 636 637 st = jabber_write_packet(ic, node); 638 639 xt_free_node(node); 669 640 return st; 670 641 } 671 642 672 xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig);673 674 xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid)643 xt_status jabber_iq_parse_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 644 645 xt_status jabber_iq_query_features(struct im_connection *ic, char *bare_jid) 675 646 { 676 647 struct xt_node *node, *query; 677 648 struct jabber_buddy *bud; 678 679 if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL ) 680 { 649 650 if ((bud = jabber_buddy_by_jid(ic, bare_jid, 0)) == NULL) { 681 651 /* Who cares about the unknown... */ 682 imcb_log( 683 return XT_HANDLED; 684 } 685 686 if ( bud->features )/* been here already */687 return XT_HANDLED; 688 689 node = xt_new_node( "query", NULL, NULL ); 690 xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO);691 692 if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) ) 693 {694 imcb_log( ic, "WARNING: Couldn't generate feature query");695 xt_free_node( node);696 return XT_HANDLED; 697 } 698 699 jabber_cache_add( ic, query, jabber_iq_parse_features);700 701 return jabber_write_packet( ic, query) ? XT_HANDLED : XT_ABORT;702 } 703 704 xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig)652 imcb_log(ic, "Couldn't find buddy: %s", bare_jid); 653 return XT_HANDLED; 654 } 655 656 if (bud->features) { /* been here already */ 657 return XT_HANDLED; 658 } 659 660 node = xt_new_node("query", NULL, NULL); 661 xt_add_attr(node, "xmlns", XMLNS_DISCO_INFO); 662 663 if (!(query = jabber_make_packet("iq", "get", bare_jid, node))) { 664 imcb_log(ic, "WARNING: Couldn't generate feature query"); 665 xt_free_node(node); 666 return XT_HANDLED; 667 } 668 669 jabber_cache_add(ic, query, jabber_iq_parse_features); 670 671 return jabber_write_packet(ic, query) ? XT_HANDLED : XT_ABORT; 672 } 673 674 xt_status jabber_iq_parse_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 705 675 { 706 676 struct xt_node *c; … … 708 678 char *feature, *xmlns, *from; 709 679 710 if( !( from = xt_find_attr( node, "from" ) ) || 711 !( c = xt_find_node( node->children, "query" ) ) || 712 !( xmlns = xt_find_attr( c, "xmlns" ) ) || 713 !( strcmp( xmlns, XMLNS_DISCO_INFO ) == 0 ) ) 714 { 715 imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" ); 716 return XT_HANDLED; 717 } 718 if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL ) 719 { 680 if (!(from = xt_find_attr(node, "from")) || 681 !(c = xt_find_node(node->children, "query")) || 682 !(xmlns = xt_find_attr(c, "xmlns")) || 683 !(strcmp(xmlns, XMLNS_DISCO_INFO) == 0)) { 684 imcb_log(ic, "WARNING: Received incomplete IQ-result packet for discover"); 685 return XT_HANDLED; 686 } 687 if ((bud = jabber_buddy_by_jid(ic, from, 0)) == NULL) { 720 688 /* Who cares about the unknown... */ 721 imcb_log( ic, "Couldn't find buddy: %s", from);722 return XT_HANDLED; 723 } 724 689 imcb_log(ic, "Couldn't find buddy: %s", from); 690 return XT_HANDLED; 691 } 692 725 693 c = c->children; 726 while ( ( c = xt_find_node( c, "feature" ) ) )727 {728 feature = xt_find_attr( c, "var" );729 if( feature )730 bud->features = g_slist_append( bud->features, g_strdup( feature ) );694 while ((c = xt_find_node(c, "feature"))) { 695 feature = xt_find_attr(c, "var"); 696 if (feature) { 697 bud->features = g_slist_append(bud->features, g_strdup(feature)); 698 } 731 699 c = c->next; 732 700 } … … 735 703 } 736 704 737 xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig);738 739 xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns)705 xt_status jabber_iq_parse_server_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 706 707 xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns) 740 708 { 741 709 struct xt_node *node, *query; 742 710 struct jabber_data *jd = ic->proto_data; 743 744 node = xt_new_node( "query", NULL, NULL ); 745 xt_add_attr( node, "xmlns", xmlns ); 746 747 if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) ) 748 { 749 imcb_log( ic, "WARNING: Couldn't generate server query" ); 750 xt_free_node( node ); 711 712 node = xt_new_node("query", NULL, NULL); 713 xt_add_attr(node, "xmlns", xmlns); 714 715 if (!(query = jabber_make_packet("iq", "get", jid, node))) { 716 imcb_log(ic, "WARNING: Couldn't generate server query"); 717 xt_free_node(node); 751 718 } 752 719 753 720 jd->have_streamhosts--; 754 jabber_cache_add( ic, query, jabber_iq_parse_server_features);755 756 return jabber_write_packet( ic, query) ? XT_HANDLED : XT_ABORT;721 jabber_cache_add(ic, query, jabber_iq_parse_server_features); 722 723 return jabber_write_packet(ic, query) ? XT_HANDLED : XT_ABORT; 757 724 } 758 725 … … 760 727 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info 761 728 */ 762 xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig)729 xt_status jabber_iq_parse_server_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 763 730 { 764 731 struct xt_node *c; … … 766 733 char *xmlns, *from; 767 734 768 if( !( c = xt_find_node( node->children, "query" ) ) || 769 !( from = xt_find_attr( node, "from" ) ) || 770 !( xmlns = xt_find_attr( c, "xmlns" ) ) ) 771 { 772 imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" ); 735 if (!(c = xt_find_node(node->children, "query")) || 736 !(from = xt_find_attr(node, "from")) || 737 !(xmlns = xt_find_attr(c, "xmlns"))) { 738 imcb_log(ic, "WARNING: Received incomplete IQ-result packet for discover"); 773 739 return XT_HANDLED; 774 740 } … … 776 742 jd->have_streamhosts++; 777 743 778 if( strcmp( xmlns, XMLNS_DISCO_ITEMS ) == 0 ) 779 { 744 if (strcmp(xmlns, XMLNS_DISCO_ITEMS) == 0) { 780 745 char *itemjid; 781 746 782 747 /* answer from server */ 783 748 784 749 c = c->children; 785 while ( ( c = xt_find_node( c, "item" ) ) )786 {787 itemjid = xt_find_attr( c, "jid" ); 788 789 if( itemjid )790 jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );750 while ((c = xt_find_node(c, "item"))) { 751 itemjid = xt_find_attr(c, "jid"); 752 753 if (itemjid) { 754 jabber_iq_query_server(ic, itemjid, XMLNS_DISCO_INFO); 755 } 791 756 792 757 c = c->next; 793 758 } 794 } 795 else if( strcmp( xmlns, XMLNS_DISCO_INFO ) == 0 ) 796 { 759 } else if (strcmp(xmlns, XMLNS_DISCO_INFO) == 0) { 797 760 char *category, *type; 798 761 … … 800 763 801 764 c = c->children; 802 while ( ( c = xt_find_node( c, "identity" ) ) )803 {804 category = xt_find_attr( c, "category");805 type = xt_find_attr( c, "type" ); 806 807 if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&808 category && ( strcmp( category, "proxy" ) == 0 ) )809 jabber_iq_query_server( ic, from, XMLNS_BYTESTREAMS );765 while ((c = xt_find_node(c, "identity"))) { 766 category = xt_find_attr(c, "category"); 767 type = xt_find_attr(c, "type"); 768 769 if (type && (strcmp(type, "bytestreams") == 0) && 770 category && (strcmp(category, "proxy") == 0)) { 771 jabber_iq_query_server(ic, from, XMLNS_BYTESTREAMS); 772 } 810 773 811 774 c = c->next; 812 775 } 813 } 814 else if( strcmp( xmlns, XMLNS_BYTESTREAMS ) == 0 ) 815 { 776 } else if (strcmp(xmlns, XMLNS_BYTESTREAMS) == 0) { 816 777 char *host, *jid, *port_s; 817 778 int port; … … 819 780 /* answer from proxy */ 820 781 821 if( ( c = xt_find_node( c->children, "streamhost" ) ) && 822 ( host = xt_find_attr( c, "host" ) ) && 823 ( port_s = xt_find_attr( c, "port" ) ) && 824 ( sscanf( port_s, "%d", &port ) == 1 ) && 825 ( jid = xt_find_attr( c, "jid" ) ) ) 826 { 827 jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 ); 828 829 sh->jid = g_strdup( jid ); 830 sh->host = g_strdup( host ); 831 g_snprintf( sh->port, sizeof( sh->port ), "%u", port ); 832 833 imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port ); 834 jd->streamhosts = g_slist_append( jd->streamhosts, sh ); 835 } 836 } 837 838 if( jd->have_streamhosts == 0 ) 782 if ((c = xt_find_node(c->children, "streamhost")) && 783 (host = xt_find_attr(c, "host")) && 784 (port_s = xt_find_attr(c, "port")) && 785 (sscanf(port_s, "%d", &port) == 1) && 786 (jid = xt_find_attr(c, "jid"))) { 787 jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1); 788 789 sh->jid = g_strdup(jid); 790 sh->host = g_strdup(host); 791 g_snprintf(sh->port, sizeof(sh->port), "%u", port); 792 793 imcb_log(ic, "Proxy found: jid %s host %s port %u", jid, host, port); 794 jd->streamhosts = g_slist_append(jd->streamhosts, sh); 795 } 796 } 797 798 if (jd->have_streamhosts == 0) { 839 799 jd->have_streamhosts++; 840 841 return XT_HANDLED; 842 } 843 844 static xt_status jabber_iq_version_response( struct im_connection *ic, 845 struct xt_node *node, struct xt_node *orig ); 846 847 void jabber_iq_version_send( struct im_connection *ic, struct jabber_buddy *bud, void *data ) 800 } 801 802 return XT_HANDLED; 803 } 804 805 static xt_status jabber_iq_version_response(struct im_connection *ic, 806 struct xt_node *node, struct xt_node *orig); 807 808 void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data) 848 809 { 849 810 struct xt_node *node, *query; 850 851 node = xt_new_node( "query", NULL, NULL);852 xt_add_attr( node, "xmlns", XMLNS_VERSION);853 query = jabber_make_packet( "iq", "get", bud->full_jid, node);854 jabber_cache_add( ic, query, jabber_iq_version_response);855 856 jabber_write_packet( ic, query);857 } 858 859 static xt_status jabber_iq_version_response( 860 struct xt_node *node, struct xt_node *orig)811 812 node = xt_new_node("query", NULL, NULL); 813 xt_add_attr(node, "xmlns", XMLNS_VERSION); 814 query = jabber_make_packet("iq", "get", bud->full_jid, node); 815 jabber_cache_add(ic, query, jabber_iq_version_response); 816 817 jabber_write_packet(ic, query); 818 } 819 820 static xt_status jabber_iq_version_response(struct im_connection *ic, 821 struct xt_node *node, struct xt_node *orig) 861 822 { 862 823 struct xt_node *query; … … 866 827 bee_user_t *bu; 867 828 struct jabber_buddy *bud = NULL; 868 869 if( ( s = xt_find_attr( node, "from" ) ) && 870 ( bud = jabber_buddy_by_jid( ic, s, 0 ) ) && 871 ( query = xt_find_node( node->children, "query" ) ) && 872 ( bu = bee_user_by_handle( ic->bee, ic, bud->bare_jid ) ) ) 873 { 874 rets = g_string_new( "Resource " ); 875 g_string_append( rets, bud->resource ); 876 } 877 else 878 return XT_HANDLED; 879 880 for( query = query->children; query; query = query->next ) 881 if( query->text_len > 0 ) 882 g_string_append_printf( rets, " %s: %s,", query->name, query->text ); 883 884 g_string_truncate( rets, rets->len - 1 ); 829 830 if ((s = xt_find_attr(node, "from")) && 831 (bud = jabber_buddy_by_jid(ic, s, 0)) && 832 (query = xt_find_node(node->children, "query")) && 833 (bu = bee_user_by_handle(ic->bee, ic, bud->bare_jid))) { 834 rets = g_string_new("Resource "); 835 g_string_append(rets, bud->resource); 836 } else { 837 return XT_HANDLED; 838 } 839 840 for (query = query->children; query; query = query->next) { 841 if (query->text_len > 0) { 842 g_string_append_printf(rets, " %s: %s,", query->name, query->text); 843 } 844 } 845 846 g_string_truncate(rets, rets->len - 1); 885 847 ret[0] = rets->str; 886 imcb_buddy_action_response( bu, "VERSION", ret, NULL);887 g_string_free( rets, TRUE);888 889 return XT_HANDLED; 890 } 891 892 static xt_status jabber_iq_disco_server_response( 893 struct xt_node *node, struct xt_node *orig);894 895 static int jabber_iq_disco_server( struct im_connection *ic)848 imcb_buddy_action_response(bu, "VERSION", ret, NULL); 849 g_string_free(rets, TRUE); 850 851 return XT_HANDLED; 852 } 853 854 static xt_status jabber_iq_disco_server_response(struct im_connection *ic, 855 struct xt_node *node, struct xt_node *orig); 856 857 static int jabber_iq_disco_server(struct im_connection *ic) 896 858 { 897 859 struct xt_node *node, *iq; 898 860 struct jabber_data *jd = ic->proto_data; 899 900 node = xt_new_node( "query", NULL, NULL);901 xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO);902 iq = jabber_make_packet( "iq", "get", jd->server, node);903 904 jabber_cache_add( ic, iq, jabber_iq_disco_server_response);905 return jabber_write_packet( ic, iq);906 } 907 908 static xt_status jabber_iq_disco_server_response( 909 struct xt_node *node, struct xt_node *orig)861 862 node = xt_new_node("query", NULL, NULL); 863 xt_add_attr(node, "xmlns", XMLNS_DISCO_INFO); 864 iq = jabber_make_packet("iq", "get", jd->server, node); 865 866 jabber_cache_add(ic, iq, jabber_iq_disco_server_response); 867 return jabber_write_packet(ic, iq); 868 } 869 870 static xt_status jabber_iq_disco_server_response(struct im_connection *ic, 871 struct xt_node *node, struct xt_node *orig) 910 872 { 911 873 struct jabber_data *jd = ic->proto_data; 912 874 struct xt_node *id; 913 914 if( ( id = xt_find_path( node, "query/identity" ) ) ) 915 { 875 876 if ((id = xt_find_path(node, "query/identity"))) { 916 877 char *cat, *type, *name; 917 918 if ( !( cat = xt_find_attr( id, "category" )) ||919 !( type = xt_find_attr( id, "type" )) ||920 !( name = xt_find_attr( id, "name" ) ) )878 879 if (!(cat = xt_find_attr(id, "category")) || 880 !(type = xt_find_attr(id, "type")) || 881 !(name = xt_find_attr(id, "name"))) { 921 882 return XT_HANDLED; 922 923 if( strcmp( cat, "server" ) == 0 && strcmp( type, "im" ) == 0 && 924 strstr( name, "Google" ) != NULL ) 883 } 884 885 if (strcmp(cat, "server") == 0 && strcmp(type, "im") == 0 && 886 strstr(name, "Google") != NULL) { 925 887 jd->flags |= JFLAG_GTALK; 926 } 927 928 return XT_HANDLED; 929 } 888 } 889 } 890 891 return XT_HANDLED; 892 } -
protocols/jabber/jabber.c
raf359b4 r5ebff60 54 54 }; 55 55 56 static void jabber_init( account_t *acc)56 static void jabber_init(account_t *acc) 57 57 { 58 58 set_t *s; 59 59 char str[16]; 60 61 s = set_add( &acc->set, "activity_timeout", "600", set_eval_int, acc);62 63 s = set_add( &acc->set, "oauth", "false", set_eval_oauth, acc);64 65 s = set_add( &acc->set, "display_name", NULL, NULL, acc);66 67 g_snprintf( str, sizeof( str ), "%d", jabber_port_list[0]);68 s = set_add( &acc->set, "port", str, set_eval_int, acc);60 61 s = set_add(&acc->set, "activity_timeout", "600", set_eval_int, acc); 62 63 s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc); 64 65 s = set_add(&acc->set, "display_name", NULL, NULL, acc); 66 67 g_snprintf(str, sizeof(str), "%d", jabber_port_list[0]); 68 s = set_add(&acc->set, "port", str, set_eval_int, acc); 69 69 s->flags |= ACC_SET_OFFLINE_ONLY; 70 71 s = set_add( &acc->set, "priority", "0", set_eval_priority, acc);72 73 s = set_add( &acc->set, "proxy", "<local>;<auto>", NULL, acc);74 75 s = set_add( &acc->set, "resource", "BitlBee", NULL, acc);70 71 s = set_add(&acc->set, "priority", "0", set_eval_priority, acc); 72 73 s = set_add(&acc->set, "proxy", "<local>;<auto>", NULL, acc); 74 75 s = set_add(&acc->set, "resource", "BitlBee", NULL, acc); 76 76 s->flags |= ACC_SET_OFFLINE_ONLY; 77 78 s = set_add( &acc->set, "resource_select", "activity", NULL, acc);79 80 s = set_add( &acc->set, "sasl", "true", set_eval_bool, acc);77 78 s = set_add(&acc->set, "resource_select", "activity", NULL, acc); 79 80 s = set_add(&acc->set, "sasl", "true", set_eval_bool, acc); 81 81 s->flags |= ACC_SET_OFFLINE_ONLY | SET_HIDDEN_DEFAULT; 82 83 s = set_add( &acc->set, "server", NULL, set_eval_account, acc);82 83 s = set_add(&acc->set, "server", NULL, set_eval_account, acc); 84 84 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK; 85 86 s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc);85 86 s = set_add(&acc->set, "ssl", "false", set_eval_bool, acc); 87 87 s->flags |= ACC_SET_OFFLINE_ONLY; 88 89 s = set_add( &acc->set, "tls", "true", set_eval_tls, acc);88 89 s = set_add(&acc->set, "tls", "true", set_eval_tls, acc); 90 90 s->flags |= ACC_SET_OFFLINE_ONLY; 91 92 s = set_add( &acc->set, "tls_verify", "true", set_eval_bool, acc);91 92 s = set_add(&acc->set, "tls_verify", "true", set_eval_bool, acc); 93 93 s->flags |= ACC_SET_OFFLINE_ONLY; 94 94 95 s = set_add( &acc->set, "user_agent", "BitlBee", NULL, acc);96 97 s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc);95 s = set_add(&acc->set, "user_agent", "BitlBee", NULL, acc); 96 97 s = set_add(&acc->set, "xmlconsole", "false", set_eval_bool, acc); 98 98 s->flags |= ACC_SET_OFFLINE_ONLY; 99 99 100 100 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE | 101 101 ACC_FLAG_HANDLE_DOMAINS; 102 102 } 103 103 104 static void jabber_generate_id_hash( struct jabber_data *jd);105 106 static void jabber_login( account_t *acc)107 { 108 struct im_connection *ic = imcb_new( acc);109 struct jabber_data *jd = g_new0( struct jabber_data, 1);104 static void jabber_generate_id_hash(struct jabber_data *jd); 105 106 static void jabber_login(account_t *acc) 107 { 108 struct im_connection *ic = imcb_new(acc); 109 struct jabber_data *jd = g_new0(struct jabber_data, 1); 110 110 char *s; 111 111 112 112 /* For now this is needed in the _connected() handlers if using 113 113 GLib event handling, to make sure we're not handling events 114 114 on dead connections. */ 115 jabber_connections = g_slist_prepend( jabber_connections, ic);116 115 jabber_connections = g_slist_prepend(jabber_connections, ic); 116 117 117 jd->ic = ic; 118 118 ic->proto_data = jd; 119 120 jabber_set_me( ic, acc->user);121 119 120 jabber_set_me(ic, acc->user); 121 122 122 jd->fd = jd->r_inpa = jd->w_inpa = -1; 123 124 if( jd->server == NULL ) 125 { 126 imcb_error( ic, "Incomplete account name (format it like <username@jabberserver.name>)" ); 127 imc_logout( ic, FALSE ); 123 124 if (jd->server == NULL) { 125 imcb_error(ic, "Incomplete account name (format it like <username@jabberserver.name>)"); 126 imc_logout(ic, FALSE); 128 127 return; 129 128 } 130 131 if( ( s = strchr( jd->server, '/' ) ) ) 132 { 129 130 if ((s = strchr(jd->server, '/'))) { 133 131 *s = 0; 134 set_setstr( &acc->set, "resource", s + 1);135 132 set_setstr(&acc->set, "resource", s + 1); 133 136 134 /* Also remove the /resource from the original variable so we 137 135 won't have to do this again every time. */ 138 s = strchr( acc->user, '/');136 s = strchr(acc->user, '/'); 139 137 *s = 0; 140 138 } 141 142 jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free ); 143 jd->buddies = g_hash_table_new( g_str_hash, g_str_equal ); 144 145 if( set_getbool( &acc->set, "oauth" ) ) 146 { 139 140 jd->node_cache = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, jabber_cache_entry_free); 141 jd->buddies = g_hash_table_new(g_str_hash, g_str_equal); 142 143 if (set_getbool(&acc->set, "oauth")) { 147 144 GSList *p_in = NULL; 148 145 const char *tok; 149 146 150 147 jd->fd = jd->r_inpa = jd->w_inpa = -1; 151 152 if ( strstr( jd->server, ".facebook.com" ) )148 149 if (strstr(jd->server, ".facebook.com")) { 153 150 jd->oauth2_service = &oauth2_service_facebook; 154 else151 } else { 155 152 jd->oauth2_service = &oauth2_service_google; 156 157 oauth_params_parse( &p_in, ic->acc->pass ); 158 153 } 154 155 oauth_params_parse(&p_in, ic->acc->pass); 156 159 157 /* First see if we have a refresh token, in which case any 160 158 access token we *might* have has probably expired already 161 159 anyway. */ 162 if( ( tok = oauth_params_get( &p_in, "refresh_token" ) ) ) 163 { 164 sasl_oauth2_refresh( ic, tok ); 160 if ((tok = oauth_params_get(&p_in, "refresh_token"))) { 161 sasl_oauth2_refresh(ic, tok); 165 162 } 166 163 /* If we don't have a refresh token, let's hope the access 167 164 token is still usable. */ 168 else if( ( tok = oauth_params_get( &p_in, "access_token" ) ) ) 169 { 170 jd->oauth2_access_token = g_strdup( tok ); 171 jabber_connect( ic ); 165 else if ((tok = oauth_params_get(&p_in, "access_token"))) { 166 jd->oauth2_access_token = g_strdup(tok); 167 jabber_connect(ic); 172 168 } 173 169 /* If we don't have any, start the OAuth process now. Don't 174 170 even open an XMPP connection yet. */ 175 else 176 { 177 sasl_oauth2_init( ic ); 171 else { 172 sasl_oauth2_init(ic); 178 173 ic->flags |= OPT_SLOW_LOGIN; 179 174 } 180 181 oauth_params_free( &p_in);182 } 183 else184 jabber_connect( ic );175 176 oauth_params_free(&p_in); 177 } else { 178 jabber_connect(ic); 179 } 185 180 } 186 181 187 182 /* Separate this from jabber_login() so we can do OAuth first if necessary. 188 183 Putting this in io.c would probably be more correct. */ 189 void jabber_connect( struct im_connection *ic)184 void jabber_connect(struct im_connection *ic) 190 185 { 191 186 account_t *acc = ic->acc; … … 194 189 char *connect_to; 195 190 struct ns_srv_reply **srvl = NULL, *srv = NULL; 196 191 197 192 /* Figure out the hostname to connect to. */ 198 if ( acc->server && *acc->server )193 if (acc->server && *acc->server) { 199 194 connect_to = acc->server; 200 else if( ( srvl = srv_lookup( "xmpp-client", "tcp", jd->server ) ) || 201 ( srvl = srv_lookup( "jabber-client", "tcp", jd->server ) ) ) 202 { 195 } else if ((srvl = srv_lookup("xmpp-client", "tcp", jd->server)) || 196 (srvl = srv_lookup("jabber-client", "tcp", jd->server))) { 203 197 /* Find the lowest-priority one. These usually come 204 198 back in random/shuffled order. Not looking at 205 199 weights etc for now. */ 206 200 srv = *srvl; 207 for ( i = 1; srvl[i]; i ++ )208 if ( srvl[i]->prio < srv->prio )201 for (i = 1; srvl[i]; i++) { 202 if (srvl[i]->prio < srv->prio) { 209 203 srv = srvl[i]; 210 204 } 205 } 206 211 207 connect_to = srv->name; 212 } 213 else 208 } else { 214 209 connect_to = jd->server; 215 216 imcb_log( ic, "Connecting" ); 217 218 for( i = 0; jabber_port_list[i] > 0; i ++ ) 219 if( set_getint( &acc->set, "port" ) == jabber_port_list[i] ) 210 } 211 212 imcb_log(ic, "Connecting"); 213 214 for (i = 0; jabber_port_list[i] > 0; i++) { 215 if (set_getint(&acc->set, "port") == jabber_port_list[i]) { 220 216 break; 221 222 if( jabber_port_list[i] == 0 ) 223 { 224 imcb_log( ic, "Illegal port number" ); 225 imc_logout( ic, FALSE ); 217 } 218 } 219 220 if (jabber_port_list[i] == 0) { 221 imcb_log(ic, "Illegal port number"); 222 imc_logout(ic, FALSE); 226 223 return; 227 224 } 228 225 229 226 /* For non-SSL connections we can try to use the port # from the SRV 230 227 reply, but let's not do that when using SSL, SSL usually runs on 231 228 non-standard ports... */ 232 if( set_getbool( &acc->set, "ssl" ) ) 233 { 234 jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), set_getbool( &acc->set, "tls_verify" ), jabber_connected_ssl, ic ); 235 jd->fd = jd->ssl ? ssl_getfd( jd->ssl ) : -1; 236 } 237 else 238 { 239 jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, ic ); 240 } 241 srv_free( srvl ); 242 243 if( jd->fd == -1 ) 244 { 245 imcb_error( ic, "Could not connect to server" ); 246 imc_logout( ic, TRUE ); 247 229 if (set_getbool(&acc->set, "ssl")) { 230 jd->ssl = ssl_connect(connect_to, set_getint(&acc->set, "port"), set_getbool(&acc->set, 231 "tls_verify"), jabber_connected_ssl, 232 ic); 233 jd->fd = jd->ssl ? ssl_getfd(jd->ssl) : -1; 234 } else { 235 jd->fd = proxy_connect(connect_to, srv ? srv->port : set_getint(&acc->set, 236 "port"), jabber_connected_plain, ic); 237 } 238 srv_free(srvl); 239 240 if (jd->fd == -1) { 241 imcb_error(ic, "Could not connect to server"); 242 imc_logout(ic, TRUE); 243 248 244 return; 249 245 } 250 251 if( set_getbool( &acc->set, "xmlconsole" ) ) 252 { 246 247 if (set_getbool(&acc->set, "xmlconsole")) { 253 248 jd->flags |= JFLAG_XMLCONSOLE; 254 249 /* Shouldn't really do this at this stage already, maybe. But 255 250 I think this shouldn't break anything. */ 256 imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL);257 } 258 259 jabber_generate_id_hash( jd);251 imcb_add_buddy(ic, JABBER_XMLCONSOLE_HANDLE, NULL); 252 } 253 254 jabber_generate_id_hash(jd); 260 255 } 261 256 262 257 /* This generates an unfinished md5_state_t variable. Every time we generate 263 258 an ID, we finish the state by adding a sequence number and take the hash. */ 264 static void jabber_generate_id_hash( struct jabber_data *jd)259 static void jabber_generate_id_hash(struct jabber_data *jd) 265 260 { 266 261 md5_byte_t binbuf[4]; 267 262 char *s; 268 269 md5_init( &jd->cached_id_prefix);270 md5_append( &jd->cached_id_prefix, (unsigned char *) jd->username, strlen( jd->username ));271 md5_append( &jd->cached_id_prefix, (unsigned char *) jd->server, strlen( jd->server ));272 s = set_getstr( &jd->ic->acc->set, "resource");273 md5_append( &jd->cached_id_prefix, (unsigned char *) s, strlen( s ));274 random_bytes( binbuf, 4);275 md5_append( &jd->cached_id_prefix, binbuf, 4);276 } 277 278 static void jabber_logout( struct im_connection *ic)279 { 280 struct jabber_data *jd = ic->proto_data; 281 282 while ( jd->filetransfers )283 imcb_file_canceled( ic, ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out");284 285 while( jd->streamhosts ) 286 {263 264 md5_init(&jd->cached_id_prefix); 265 md5_append(&jd->cached_id_prefix, (unsigned char *) jd->username, strlen(jd->username)); 266 md5_append(&jd->cached_id_prefix, (unsigned char *) jd->server, strlen(jd->server)); 267 s = set_getstr(&jd->ic->acc->set, "resource"); 268 md5_append(&jd->cached_id_prefix, (unsigned char *) s, strlen(s)); 269 random_bytes(binbuf, 4); 270 md5_append(&jd->cached_id_prefix, binbuf, 4); 271 } 272 273 static void jabber_logout(struct im_connection *ic) 274 { 275 struct jabber_data *jd = ic->proto_data; 276 277 while (jd->filetransfers) { 278 imcb_file_canceled(ic, (( struct jabber_transfer *) jd->filetransfers->data)->ft, "Logging out"); 279 } 280 281 while (jd->streamhosts) { 287 282 jabber_streamhost_t *sh = jd->streamhosts->data; 288 jd->streamhosts = g_slist_remove( jd->streamhosts, sh ); 289 g_free( sh->jid ); 290 g_free( sh->host ); 291 g_free( sh ); 292 } 293 294 if( jd->fd >= 0 ) 295 jabber_end_stream( ic ); 296 297 while( ic->groupchats ) 298 jabber_chat_free( ic->groupchats->data ); 299 300 if( jd->r_inpa >= 0 ) 301 b_event_remove( jd->r_inpa ); 302 if( jd->w_inpa >= 0 ) 303 b_event_remove( jd->w_inpa ); 304 305 if( jd->ssl ) 306 ssl_disconnect( jd->ssl ); 307 if( jd->fd >= 0 ) 308 closesocket( jd->fd ); 309 310 if( jd->tx_len ) 311 g_free( jd->txq ); 312 313 if( jd->node_cache ) 314 g_hash_table_destroy( jd->node_cache ); 315 316 jabber_buddy_remove_all( ic ); 317 318 xt_free( jd->xt ); 319 320 md5_free( &jd->cached_id_prefix ); 321 322 g_free( jd->oauth2_access_token ); 323 g_free( jd->away_message ); 324 g_free( jd->internal_jid ); 325 g_free( jd->username ); 326 g_free( jd->me ); 327 g_free( jd ); 328 329 jabber_connections = g_slist_remove( jabber_connections, ic ); 330 } 331 332 static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, int flags ) 283 jd->streamhosts = g_slist_remove(jd->streamhosts, sh); 284 g_free(sh->jid); 285 g_free(sh->host); 286 g_free(sh); 287 } 288 289 if (jd->fd >= 0) { 290 jabber_end_stream(ic); 291 } 292 293 while (ic->groupchats) { 294 jabber_chat_free(ic->groupchats->data); 295 } 296 297 if (jd->r_inpa >= 0) { 298 b_event_remove(jd->r_inpa); 299 } 300 if (jd->w_inpa >= 0) { 301 b_event_remove(jd->w_inpa); 302 } 303 304 if (jd->ssl) { 305 ssl_disconnect(jd->ssl); 306 } 307 if (jd->fd >= 0) { 308 closesocket(jd->fd); 309 } 310 311 if (jd->tx_len) { 312 g_free(jd->txq); 313 } 314 315 if (jd->node_cache) { 316 g_hash_table_destroy(jd->node_cache); 317 } 318 319 jabber_buddy_remove_all(ic); 320 321 xt_free(jd->xt); 322 323 md5_free(&jd->cached_id_prefix); 324 325 g_free(jd->oauth2_access_token); 326 g_free(jd->away_message); 327 g_free(jd->internal_jid); 328 g_free(jd->username); 329 g_free(jd->me); 330 g_free(jd); 331 332 jabber_connections = g_slist_remove(jabber_connections, ic); 333 } 334 335 static int jabber_buddy_msg(struct im_connection *ic, char *who, char *message, int flags) 333 336 { 334 337 struct jabber_data *jd = ic->proto_data; … … 337 340 char *s; 338 341 int st; 339 340 if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) 341 return jabber_write( ic, message, strlen( message ) ); 342 343 if( g_strcasecmp( who, JABBER_OAUTH_HANDLE ) == 0 && 344 !( jd->flags & OPT_LOGGED_IN ) && jd->fd == -1 ) 345 { 346 if( sasl_oauth2_get_refresh_token( ic, message ) ) 347 { 342 343 if (g_strcasecmp(who, JABBER_XMLCONSOLE_HANDLE) == 0) { 344 return jabber_write(ic, message, strlen(message)); 345 } 346 347 if (g_strcasecmp(who, JABBER_OAUTH_HANDLE) == 0 && 348 !(jd->flags & OPT_LOGGED_IN) && jd->fd == -1) { 349 if (sasl_oauth2_get_refresh_token(ic, message)) { 348 350 return 1; 349 } 350 else 351 { 352 imcb_error( ic, "OAuth failure" ); 353 imc_logout( ic, TRUE ); 351 } else { 352 imcb_error(ic, "OAuth failure"); 353 imc_logout(ic, TRUE); 354 354 return 0; 355 355 } 356 356 } 357 358 if ( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) )359 bud = jabber_buddy_by_ext_jid( ic, who, 0);360 else361 bud = jabber_buddy_by_jid( ic, who, GET_BUDDY_BARE_OK);362 363 node = xt_new_node( "body", message, NULL ); 364 node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node);365 366 if( bud && ( jd->flags & JFLAG_WANT_TYPING ) && 367 ( ( bud->flags & JBFLAG_DOES_XEP85 ) ||368 !( bud->flags & JBFLAG_PROBED_XEP85 ) ) )369 {357 358 if ((s = strchr(who, '=')) && jabber_chat_by_jid(ic, s + 1)) { 359 bud = jabber_buddy_by_ext_jid(ic, who, 0); 360 } else { 361 bud = jabber_buddy_by_jid(ic, who, GET_BUDDY_BARE_OK); 362 } 363 364 node = xt_new_node("body", message, NULL); 365 node = jabber_make_packet("message", "chat", bud ? bud->full_jid : who, node); 366 367 if (bud && (jd->flags & JFLAG_WANT_TYPING) && 368 ((bud->flags & JBFLAG_DOES_XEP85) || 369 !(bud->flags & JBFLAG_PROBED_XEP85))) { 370 370 struct xt_node *act; 371 371 372 372 /* If the user likes typing notification and if we don't know 373 373 (and didn't probe before) if this resource supports XEP85, … … 376 376 tag to tell that the user stopped typing (well, that's what 377 377 we guess when s/he pressed Enter...). */ 378 act = xt_new_node( "active", NULL, NULL);379 xt_add_attr( act, "xmlns", XMLNS_CHATSTATES);380 xt_add_child( node, act);381 378 act = xt_new_node("active", NULL, NULL); 379 xt_add_attr(act, "xmlns", XMLNS_CHATSTATES); 380 xt_add_child(node, act); 381 382 382 /* Just make sure we do this only once. */ 383 383 bud->flags |= JBFLAG_PROBED_XEP85; 384 384 } 385 386 st = jabber_write_packet( ic, node);387 xt_free_node( node);388 385 386 st = jabber_write_packet(ic, node); 387 xt_free_node(node); 388 389 389 return st; 390 390 } 391 391 392 static GList *jabber_away_states( struct im_connection *ic)392 static GList *jabber_away_states(struct im_connection *ic) 393 393 { 394 394 static GList *l = NULL; 395 395 int i; 396 397 if( l == NULL ) 398 for( i = 0; jabber_away_state_list[i].full_name; i ++ ) 399 l = g_list_append( l, (void*) jabber_away_state_list[i].full_name ); 400 396 397 if (l == NULL) { 398 for (i = 0; jabber_away_state_list[i].full_name; i++) { 399 l = g_list_append(l, (void *) jabber_away_state_list[i].full_name); 400 } 401 } 402 401 403 return l; 402 404 } 403 405 404 static void jabber_get_info( struct im_connection *ic, char *who)406 static void jabber_get_info(struct im_connection *ic, char *who) 405 407 { 406 408 struct jabber_buddy *bud; 407 408 bud = jabber_buddy_by_jid( ic, who, GET_BUDDY_FIRST);409 410 while ( bud )411 {412 i mcb_log( ic, "Buddy %s (%d) information:", bud->full_jid, bud->priority );413 if( bud->away_state )414 imcb_log( ic, "Away state: %s", bud->away_state->full_name );415 imcb_log( ic, "Status message: %s", bud->away_message ? bud->away_message : "(none)");416 409 410 bud = jabber_buddy_by_jid(ic, who, GET_BUDDY_FIRST); 411 412 while (bud) { 413 imcb_log(ic, "Buddy %s (%d) information:", bud->full_jid, bud->priority); 414 if (bud->away_state) { 415 imcb_log(ic, "Away state: %s", bud->away_state->full_name); 416 } 417 imcb_log(ic, "Status message: %s", bud->away_message ? bud->away_message : "(none)"); 418 417 419 bud = bud->next; 418 420 } 419 420 jabber_get_vcard( ic, bud ? bud->full_jid : who);421 } 422 423 static void jabber_set_away( struct im_connection *ic, char *state_txt, char *message)424 { 425 struct jabber_data *jd = ic->proto_data; 426 421 422 jabber_get_vcard(ic, bud ? bud->full_jid : who); 423 } 424 425 static void jabber_set_away(struct im_connection *ic, char *state_txt, char *message) 426 { 427 struct jabber_data *jd = ic->proto_data; 428 427 429 /* state_txt == NULL -> Not away. 428 430 Unknown state -> fall back to the first defined away state. */ 429 if ( state_txt == NULL )431 if (state_txt == NULL) { 430 432 jd->away_state = NULL; 431 else if( ( jd->away_state = jabber_away_state_by_name( state_txt ) ) == NULL )433 } else if ((jd->away_state = jabber_away_state_by_name(state_txt)) == NULL) { 432 434 jd->away_state = jabber_away_state_list; 433 434 g_free( jd->away_message ); 435 jd->away_message = ( message && *message ) ? g_strdup( message ) : NULL;436 437 presence_send_update( ic ); 438 } 439 440 static void jabber_add_buddy( struct im_connection *ic, char *who, char *group ) 441 { 442 struct jabber_data *jd = ic->proto_data; 443 444 if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) 445 {435 } 436 437 g_free(jd->away_message); 438 jd->away_message = (message && *message) ? g_strdup(message) : NULL; 439 440 presence_send_update(ic); 441 } 442 443 static void jabber_add_buddy(struct im_connection *ic, char *who, char *group) 444 { 445 struct jabber_data *jd = ic->proto_data; 446 447 if (g_strcasecmp(who, JABBER_XMLCONSOLE_HANDLE) == 0) { 446 448 jd->flags |= JFLAG_XMLCONSOLE; 447 imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL);449 imcb_add_buddy(ic, JABBER_XMLCONSOLE_HANDLE, NULL); 448 450 return; 449 451 } 450 451 if ( jabber_add_to_roster( ic, who, NULL, group ) )452 presence_send_request( ic, who, "subscribe");453 }454 455 static void jabber_remove_buddy( struct im_connection *ic, char *who, char *group ) 456 { 457 struct jabber_data *jd = ic->proto_data; 458 459 if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) 460 {452 453 if (jabber_add_to_roster(ic, who, NULL, group)) { 454 presence_send_request(ic, who, "subscribe"); 455 } 456 } 457 458 static void jabber_remove_buddy(struct im_connection *ic, char *who, char *group) 459 { 460 struct jabber_data *jd = ic->proto_data; 461 462 if (g_strcasecmp(who, JABBER_XMLCONSOLE_HANDLE) == 0) { 461 463 jd->flags &= ~JFLAG_XMLCONSOLE; 462 464 /* Not necessary for now. And for now the code isn't too … … 467 469 return; 468 470 } 469 471 470 472 /* We should always do this part. Clean up our administration a little bit. */ 471 jabber_buddy_remove_bare( ic, who ); 472 473 if( jabber_remove_from_roster( ic, who ) ) 474 presence_send_request( ic, who, "unsubscribe" ); 475 } 476 477 static struct groupchat *jabber_chat_join_( struct im_connection *ic, const char *room, const char *nick, const char *password, set_t **sets ) 473 jabber_buddy_remove_bare(ic, who); 474 475 if (jabber_remove_from_roster(ic, who)) { 476 presence_send_request(ic, who, "unsubscribe"); 477 } 478 } 479 480 static struct groupchat *jabber_chat_join_(struct im_connection *ic, const char *room, const char *nick, 481 const char *password, set_t **sets) 478 482 { 479 483 struct jabber_data *jd = ic->proto_data; 480 484 char *final_nick; 481 485 482 486 /* Ignore the passed nick parameter if we have our own default */ 483 if ( !( final_nick = set_getstr( sets, "nick" )) &&484 !( final_nick = set_getstr( &ic->acc->set, "display_name" ) )) {487 if (!(final_nick = set_getstr(sets, "nick")) && 488 !(final_nick = set_getstr(&ic->acc->set, "display_name"))) { 485 489 /* Well, whatever, actually use the provided default, then */ 486 490 final_nick = (char *) nick; 487 491 } 488 492 489 if( strchr( room, '@' ) == NULL ) 490 imcb_error( ic, "%s is not a valid Jabber room name. Maybe you mean %s@conference.%s?", 491 room, room, jd->server ); 492 else if( jabber_chat_by_jid( ic, room ) ) 493 imcb_error( ic, "Already present in chat `%s'", room ); 494 else 495 return jabber_chat_join( ic, room, final_nick, set_getstr( sets, "password" ) ); 496 493 if (strchr(room, '@') == NULL) { 494 imcb_error(ic, "%s is not a valid Jabber room name. Maybe you mean %s@conference.%s?", 495 room, room, jd->server); 496 } else if (jabber_chat_by_jid(ic, room)) { 497 imcb_error(ic, "Already present in chat `%s'", room); 498 } else { 499 return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password")); 500 } 501 497 502 return NULL; 498 503 } 499 504 500 static struct groupchat *jabber_chat_with_( struct im_connection *ic, char *who ) 501 { 502 return jabber_chat_with( ic, who ); 503 } 504 505 static void jabber_chat_msg_( struct groupchat *c, char *message, int flags ) 506 { 507 if( c && message ) 508 jabber_chat_msg( c, message, flags ); 509 } 510 511 static void jabber_chat_topic_( struct groupchat *c, char *topic ) 512 { 513 if( c && topic ) 514 jabber_chat_topic( c, topic ); 515 } 516 517 static void jabber_chat_leave_( struct groupchat *c ) 518 { 519 if( c ) 520 jabber_chat_leave( c, NULL ); 521 } 522 523 static void jabber_chat_invite_( struct groupchat *c, char *who, char *msg ) 505 static struct groupchat *jabber_chat_with_(struct im_connection *ic, char *who) 506 { 507 return jabber_chat_with(ic, who); 508 } 509 510 static void jabber_chat_msg_(struct groupchat *c, char *message, int flags) 511 { 512 if (c && message) { 513 jabber_chat_msg(c, message, flags); 514 } 515 } 516 517 static void jabber_chat_topic_(struct groupchat *c, char *topic) 518 { 519 if (c && topic) { 520 jabber_chat_topic(c, topic); 521 } 522 } 523 524 static void jabber_chat_leave_(struct groupchat *c) 525 { 526 if (c) { 527 jabber_chat_leave(c, NULL); 528 } 529 } 530 531 static void jabber_chat_invite_(struct groupchat *c, char *who, char *msg) 524 532 { 525 533 struct jabber_data *jd = c->ic->proto_data; … … 527 535 gchar *msg_alt = NULL; 528 536 529 if( msg == NULL ) 530 msg_alt = g_strdup_printf( "%s invited you to %s", jd->me, jc->name ); 531 532 if( c && who ) 533 jabber_chat_invite( c, who, msg ? msg : msg_alt ); 534 535 g_free( msg_alt ); 536 } 537 538 static void jabber_keepalive( struct im_connection *ic ) 537 if (msg == NULL) { 538 msg_alt = g_strdup_printf("%s invited you to %s", jd->me, jc->name); 539 } 540 541 if (c && who) { 542 jabber_chat_invite(c, who, msg ? msg : msg_alt); 543 } 544 545 g_free(msg_alt); 546 } 547 548 static void jabber_keepalive(struct im_connection *ic) 539 549 { 540 550 /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ 541 if ( !jabber_write( ic, "\n", 1 ) )551 if (!jabber_write(ic, "\n", 1)) { 542 552 return; 543 553 } 554 544 555 /* This runs the garbage collection every minute, which means every packet 545 556 is in the cache for about a minute (which should be enough AFAIK). */ 546 jabber_cache_clean( ic);547 } 548 549 static int jabber_send_typing( struct im_connection *ic, char *who, int typing)557 jabber_cache_clean(ic); 558 } 559 560 static int jabber_send_typing(struct im_connection *ic, char *who, int typing) 550 561 { 551 562 struct jabber_data *jd = ic->proto_data; 552 563 struct jabber_buddy *bud; 553 564 554 565 /* Enable typing notification related code from now. */ 555 566 jd->flags |= JFLAG_WANT_TYPING; 556 557 if( ( bud = jabber_buddy_by_jid( ic, who, 0 ) ) == NULL ) 558 { 567 568 if ((bud = jabber_buddy_by_jid(ic, who, 0)) == NULL) { 559 569 /* Sending typing notifications to unknown buddies is 560 570 unsupported for now. Shouldn't be a problem, I think. */ 561 571 return 0; 562 572 } 563 564 if( bud->flags & JBFLAG_DOES_XEP85 ) 565 { 573 574 if (bud->flags & JBFLAG_DOES_XEP85) { 566 575 /* We're only allowed to send this stuff if we know the other 567 576 side supports it. */ 568 577 569 578 struct xt_node *node; 570 579 char *type; 571 580 int st; 572 573 if ( typing & OPT_TYPING )581 582 if (typing & OPT_TYPING) { 574 583 type = "composing"; 575 else if( typing & OPT_THINKING )584 } else if (typing & OPT_THINKING) { 576 585 type = "paused"; 577 else586 } else { 578 587 type = "active"; 579 580 node = xt_new_node( type, NULL, NULL ); 581 xt_add_attr( node, "xmlns", XMLNS_CHATSTATES ); 582 node = jabber_make_packet( "message", "chat", bud->full_jid, node ); 583 584 st = jabber_write_packet( ic, node ); 585 xt_free_node( node ); 586 588 } 589 590 node = xt_new_node(type, NULL, NULL); 591 xt_add_attr(node, "xmlns", XMLNS_CHATSTATES); 592 node = jabber_make_packet("message", "chat", bud->full_jid, node); 593 594 st = jabber_write_packet(ic, node); 595 xt_free_node(node); 596 587 597 return st; 588 598 } 589 599 590 600 return 1; 591 601 } 592 602 593 void jabber_chat_add_settings( account_t *acc, set_t **head)603 void jabber_chat_add_settings(account_t *acc, set_t **head) 594 604 { 595 605 /* Meh. Stupid room passwords. Not trying to obfuscate/hide 596 606 them from the user for now. */ 597 set_add( head, "password", NULL, NULL, NULL);598 } 599 600 void jabber_chat_free_settings( account_t *acc, set_t **head)601 { 602 set_del( head, "password");603 } 604 605 GList *jabber_buddy_action_list( bee_user_t *bu)607 set_add(head, "password", NULL, NULL, NULL); 608 } 609 610 void jabber_chat_free_settings(account_t *acc, set_t **head) 611 { 612 set_del(head, "password"); 613 } 614 615 GList *jabber_buddy_action_list(bee_user_t *bu) 606 616 { 607 617 static GList *ret = NULL; 608 609 if( ret == NULL ) 610 { 618 619 if (ret == NULL) { 611 620 static const struct buddy_action ba[2] = { 612 621 { "VERSION", "Get client (version) information" }, 613 622 }; 614 615 ret = g_list_prepend( ret, (void*) ba + 0);616 } 617 623 624 ret = g_list_prepend(ret, (void *) ba + 0); 625 } 626 618 627 return ret; 619 628 } 620 629 621 void *jabber_buddy_action( struct bee_user *bu, const char *action, char * const args[], void *data ) 622 { 623 if( g_strcasecmp( action, "VERSION" ) == 0 ) 624 { 630 void *jabber_buddy_action(struct bee_user *bu, const char *action, char * const args[], void *data) 631 { 632 if (g_strcasecmp(action, "VERSION") == 0) { 625 633 struct jabber_buddy *bud; 626 627 if( ( bud = jabber_buddy_by_ext_jid( bu->ic, bu->handle, 0 ) ) == NULL ) 628 bud = jabber_buddy_by_jid( bu->ic, bu->handle, GET_BUDDY_FIRST ); 629 for( ; bud; bud = bud->next ) 630 jabber_iq_version_send( bu->ic, bud, data ); 631 } 632 634 635 if ((bud = jabber_buddy_by_ext_jid(bu->ic, bu->handle, 0)) == NULL) { 636 bud = jabber_buddy_by_jid(bu->ic, bu->handle, GET_BUDDY_FIRST); 637 } 638 for (; bud; bud = bud->next) { 639 jabber_iq_version_send(bu->ic, bud, data); 640 } 641 } 642 633 643 return NULL; 634 644 } 635 645 636 gboolean jabber_handle_is_self( struct im_connection *ic, const char *who ) { 637 struct jabber_data *jd = ic->proto_data; 638 return ( ( g_strcasecmp( who, ic->acc->user ) == 0 ) || 639 ( jd->internal_jid && 640 g_strcasecmp( who, jd->internal_jid ) == 0 ) ); 646 gboolean jabber_handle_is_self(struct im_connection *ic, const char *who) 647 { 648 struct jabber_data *jd = ic->proto_data; 649 650 return ((g_strcasecmp(who, ic->acc->user) == 0) || 651 (jd->internal_jid && 652 g_strcasecmp(who, jd->internal_jid) == 0)); 641 653 } 642 654 643 655 void jabber_initmodule() 644 656 { 645 struct prpl *ret = g_new0( struct prpl, 1);646 657 struct prpl *ret = g_new0(struct prpl, 1); 658 647 659 ret->name = "jabber"; 648 660 ret->mms = 0; /* no limit */ … … 673 685 ret->buddy_action = jabber_buddy_action; 674 686 675 register_protocol( ret);676 } 687 register_protocol(ret); 688 } -
protocols/jabber/jabber.h
raf359b4 r5ebff60 33 33 extern GSList *jabber_connections; 34 34 35 typedef enum 36 { 35 typedef enum { 37 36 JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream 38 37 and want to do auth. */ … … 40 39 JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after 41 40 SASL or TLS). */ 42 JFLAG_WANT_SESSION = 8, 41 JFLAG_WANT_SESSION = 8, /* Set if the server wants a <session/> tag 43 42 before we continue. */ 44 43 JFLAG_WANT_BIND = 16, /* ... for <bind> tag. */ … … 53 52 } jabber_flags_t; 54 53 55 typedef enum 56 { 54 typedef enum { 57 55 JBFLAG_PROBED_XEP85 = 1, /* Set this when we sent our probe packet to make 58 56 sure it gets sent only once. */ … … 68 66 69 67 /* Stores a streamhost's (a.k.a. proxy) data */ 70 typedef struct 71 { 68 typedef struct { 72 69 char *jid; 73 70 char *host; … … 75 72 } jabber_streamhost_t; 76 73 77 typedef enum 78 { 74 typedef enum { 79 75 JCFLAG_MESSAGE_SENT = 1, /* Set this after sending the first message, so 80 76 we can detect echoes/backlogs. */ 81 77 } jabber_chat_flags_t; 82 78 83 struct jabber_data 84 { 79 struct jabber_data { 85 80 struct im_connection *ic; 86 81 87 82 int fd; 88 83 void *ssl; … … 90 85 int tx_len; 91 86 int r_inpa, w_inpa; 92 87 93 88 struct xt_parser *xt; 94 89 jabber_flags_t flags; 95 96 char *username; 97 char *server; 98 char *me; 90 91 char *username; /* USERNAME@server */ 92 char *server; /* username@SERVER -=> server/domain, not hostname */ 93 char *me; /* bare jid */ 99 94 char *internal_jid; 100 95 101 96 const struct oauth2_service *oauth2_service; 102 97 char *oauth2_access_token; 103 98 104 99 /* After changing one of these two (or the priority setting), call 105 100 presence_send_update() to inform the server about the changes. */ 106 101 const struct jabber_away_state *away_state; 107 102 char *away_message; 108 103 109 104 md5_state_t cached_id_prefix; 110 105 GHashTable *node_cache; … … 116 111 }; 117 112 118 struct jabber_away_state 119 { 113 struct jabber_away_state { 120 114 char code[5]; 121 115 char *full_name; 122 116 }; 123 117 124 typedef xt_status (*jabber_cache_event) ( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); 125 126 struct jabber_cache_entry 127 { 118 typedef xt_status (*jabber_cache_event) (struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 119 120 struct jabber_cache_entry { 128 121 time_t saved_at; 129 122 struct xt_node *node; … … 138 131 refer to a real session and should only be used for operations that 139 132 support incomplete JIDs. */ 140 struct jabber_buddy 141 { 133 struct jabber_buddy { 142 134 char *bare_jid; 143 135 char *full_jid; 144 136 char *resource; 145 137 146 138 char *ext_jid; /* The JID to use in BitlBee. The real JID if possible, */ 147 139 /* otherwise something similar to the conference JID. */ 148 140 149 141 int priority; 150 142 struct jabber_away_state *away_state; 151 143 char *away_message; 152 144 GSList *features; 153 145 154 146 time_t last_msg; 155 147 jabber_buddy_flags_t flags; 156 148 157 149 struct jabber_buddy *next; 158 150 }; 159 151 160 struct jabber_chat 161 { 152 struct jabber_chat { 162 153 int flags; 163 154 char *name; … … 167 158 }; 168 159 169 struct jabber_transfer 170 { 160 struct jabber_transfer { 171 161 /* bitlbee's handle for this transfer */ 172 162 file_transfer_t *ft; … … 246 236 247 237 /* jabber.c */ 248 void jabber_connect( struct im_connection *ic);238 void jabber_connect(struct im_connection *ic); 249 239 250 240 /* iq.c */ 251 xt_status jabber_pkt_iq( struct xt_node *node, gpointer data);252 int jabber_init_iq_auth( struct im_connection *ic);253 xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig);254 int jabber_get_roster( struct im_connection *ic);255 int jabber_get_vcard( struct im_connection *ic, char *bare_jid);256 int jabber_add_to_roster( struct im_connection *ic, const char *handle, const char *name, const char *group);257 int jabber_remove_from_roster( struct im_connection *ic, char *handle);258 xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid);259 xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns);260 void jabber_iq_version_send( struct im_connection *ic, struct jabber_buddy *bud, void *data);241 xt_status jabber_pkt_iq(struct xt_node *node, gpointer data); 242 int jabber_init_iq_auth(struct im_connection *ic); 243 xt_status jabber_pkt_bind_sess(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 244 int jabber_get_roster(struct im_connection *ic); 245 int jabber_get_vcard(struct im_connection *ic, char *bare_jid); 246 int jabber_add_to_roster(struct im_connection *ic, const char *handle, const char *name, const char *group); 247 int jabber_remove_from_roster(struct im_connection *ic, char *handle); 248 xt_status jabber_iq_query_features(struct im_connection *ic, char *bare_jid); 249 xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns); 250 void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data); 261 251 262 252 /* si.c */ 263 int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode);264 void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who);265 void jabber_si_free_transfer( 253 int jabber_si_handle_request(struct im_connection *ic, struct xt_node *node, struct xt_node *sinode); 254 void jabber_si_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *who); 255 void jabber_si_free_transfer(file_transfer_t *ft); 266 256 267 257 /* s5bytestream.c */ 268 int jabber_bs_recv_request( 269 gboolean jabber_bs_send_start( struct jabber_transfer *tf);270 gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len);258 int jabber_bs_recv_request(struct im_connection *ic, struct xt_node *node, struct xt_node *qnode); 259 gboolean jabber_bs_send_start(struct jabber_transfer *tf); 260 gboolean jabber_bs_send_write(file_transfer_t *ft, char *buffer, unsigned int len); 271 261 272 262 /* message.c */ 273 xt_status jabber_pkt_message( struct xt_node *node, gpointer data);263 xt_status jabber_pkt_message(struct xt_node *node, gpointer data); 274 264 275 265 /* presence.c */ 276 xt_status jabber_pkt_presence( struct xt_node *node, gpointer data);277 int presence_send_update( struct im_connection *ic);278 int presence_send_request( struct im_connection *ic, char *handle, char *request);266 xt_status jabber_pkt_presence(struct xt_node *node, gpointer data); 267 int presence_send_update(struct im_connection *ic); 268 int presence_send_request(struct im_connection *ic, char *handle, char *request); 279 269 280 270 /* jabber_util.c */ 281 char *set_eval_priority( set_t *set, char *value ); 282 char *set_eval_tls( set_t *set, char *value ); 283 struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ); 284 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code ); 285 void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func ); 286 struct xt_node *jabber_cache_get( struct im_connection *ic, char *id ); 287 void jabber_cache_entry_free( gpointer entry ); 288 void jabber_cache_clean( struct im_connection *ic ); 289 xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node ); 290 const struct jabber_away_state *jabber_away_state_by_code( char *code ); 291 const struct jabber_away_state *jabber_away_state_by_name( char *name ); 292 void jabber_buddy_ask( struct im_connection *ic, char *handle ); 293 int jabber_compare_jid( const char *jid1, const char *jid2 ); 294 char *jabber_normalize( const char *orig ); 295 296 typedef enum 297 { 298 GET_BUDDY_CREAT = 1, /* Try to create it, if necessary. */ 299 GET_BUDDY_EXACT = 2, /* Get an exact match (only makes sense with bare JIDs). */ 300 GET_BUDDY_FIRST = 4, /* No selection, simply get the first resource for this JID. */ 301 GET_BUDDY_BARE = 8, /* Get the bare version of the JID (possibly inexistent). */ 302 GET_BUDDY_BARE_OK = 16, /* Allow returning a bare JID if that seems better. */ 271 char *set_eval_priority(set_t *set, char *value); 272 char *set_eval_tls(set_t *set, char *value); 273 struct xt_node *jabber_make_packet(char *name, char *type, char *to, struct xt_node *children); 274 struct xt_node *jabber_make_error_packet(struct xt_node *orig, char *err_cond, char *err_type, char *err_code); 275 void jabber_cache_add(struct im_connection *ic, struct xt_node *node, jabber_cache_event func); 276 struct xt_node *jabber_cache_get(struct im_connection *ic, char *id); 277 void jabber_cache_entry_free(gpointer entry); 278 void jabber_cache_clean(struct im_connection *ic); 279 xt_status jabber_cache_handle_packet(struct im_connection *ic, struct xt_node *node); 280 const struct jabber_away_state *jabber_away_state_by_code(char *code); 281 const struct jabber_away_state *jabber_away_state_by_name(char *name); 282 void jabber_buddy_ask(struct im_connection *ic, char *handle); 283 int jabber_compare_jid(const char *jid1, const char *jid2); 284 char *jabber_normalize(const char *orig); 285 286 typedef enum { 287 GET_BUDDY_CREAT = 1, /* Try to create it, if necessary. */ 288 GET_BUDDY_EXACT = 2, /* Get an exact match (only makes sense with bare JIDs). */ 289 GET_BUDDY_FIRST = 4, /* No selection, simply get the first resource for this JID. */ 290 GET_BUDDY_BARE = 8, /* Get the bare version of the JID (possibly inexistent). */ 291 GET_BUDDY_BARE_OK = 16, /* Allow returning a bare JID if that seems better. */ 303 292 } get_buddy_flags_t; 304 293 305 struct jabber_error 306 { 294 struct jabber_error { 307 295 char *code, *text, *type; 308 296 }; 309 297 310 struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid);311 struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags);312 struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags);313 int jabber_buddy_remove( struct im_connection *ic, char *full_jid);314 int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid);315 void jabber_buddy_remove_all( struct im_connection *ic);316 time_t jabber_get_timestamp( struct xt_node *xt);317 struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns);318 void jabber_error_free( struct jabber_error *err);319 gboolean jabber_set_me( struct im_connection *ic, const char *me);298 struct jabber_buddy *jabber_buddy_add(struct im_connection *ic, char *full_jid); 299 struct jabber_buddy *jabber_buddy_by_jid(struct im_connection *ic, char *jid, get_buddy_flags_t flags); 300 struct jabber_buddy *jabber_buddy_by_ext_jid(struct im_connection *ic, char *jid, get_buddy_flags_t flags); 301 int jabber_buddy_remove(struct im_connection *ic, char *full_jid); 302 int jabber_buddy_remove_bare(struct im_connection *ic, char *bare_jid); 303 void jabber_buddy_remove_all(struct im_connection *ic); 304 time_t jabber_get_timestamp(struct xt_node *xt); 305 struct jabber_error *jabber_error_parse(struct xt_node *node, char *xmlns); 306 void jabber_error_free(struct jabber_error *err); 307 gboolean jabber_set_me(struct im_connection *ic, const char *me); 320 308 321 309 extern const struct jabber_away_state jabber_away_state_list[]; 322 310 323 311 /* io.c */ 324 int jabber_write_packet( struct im_connection *ic, struct xt_node *node);325 int jabber_write( struct im_connection *ic, char *buf, int len);326 gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond);327 gboolean jabber_connected_ssl( gpointer data, int returncode, void *source, b_input_condition cond);328 gboolean jabber_start_stream( struct im_connection *ic);329 void jabber_end_stream( struct im_connection *ic);312 int jabber_write_packet(struct im_connection *ic, struct xt_node *node); 313 int jabber_write(struct im_connection *ic, char *buf, int len); 314 gboolean jabber_connected_plain(gpointer data, gint source, b_input_condition cond); 315 gboolean jabber_connected_ssl(gpointer data, int returncode, void *source, b_input_condition cond); 316 gboolean jabber_start_stream(struct im_connection *ic); 317 void jabber_end_stream(struct im_connection *ic); 330 318 331 319 /* sasl.c */ 332 xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data);333 xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data);334 xt_status sasl_pkt_result( struct xt_node *node, gpointer data);335 gboolean sasl_supported( struct im_connection *ic);336 void sasl_oauth2_init( struct im_connection *ic);337 int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg);338 int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token);320 xt_status sasl_pkt_mechanisms(struct xt_node *node, gpointer data); 321 xt_status sasl_pkt_challenge(struct xt_node *node, gpointer data); 322 xt_status sasl_pkt_result(struct xt_node *node, gpointer data); 323 gboolean sasl_supported(struct im_connection *ic); 324 void sasl_oauth2_init(struct im_connection *ic); 325 int sasl_oauth2_get_refresh_token(struct im_connection *ic, const char *msg); 326 int sasl_oauth2_refresh(struct im_connection *ic, const char *refresh_token); 339 327 340 328 extern const struct oauth2_service oauth2_service_google; … … 342 330 343 331 /* conference.c */ 344 struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password);345 struct groupchat *jabber_chat_with( struct im_connection *ic, char *who);346 struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name);347 void jabber_chat_free( struct groupchat *c);348 int jabber_chat_msg( struct groupchat *ic, char *message, int flags);349 int jabber_chat_topic( struct groupchat *c, char *topic);350 int jabber_chat_leave( struct groupchat *c, const char *reason);351 void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node);352 void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node);353 void jabber_chat_invite( struct groupchat *c, char *who, char *message);332 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password); 333 struct groupchat *jabber_chat_with(struct im_connection *ic, char *who); 334 struct groupchat *jabber_chat_by_jid(struct im_connection *ic, const char *name); 335 void jabber_chat_free(struct groupchat *c); 336 int jabber_chat_msg(struct groupchat *ic, char *message, int flags); 337 int jabber_chat_topic(struct groupchat *c, char *topic); 338 int jabber_chat_leave(struct groupchat *c, const char *reason); 339 void jabber_chat_pkt_presence(struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node); 340 void jabber_chat_pkt_message(struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node); 341 void jabber_chat_invite(struct groupchat *c, char *who, char *message); 354 342 355 343 #endif -
protocols/jabber/jabber_util.c
raf359b4 r5ebff60 4 4 * Jabber module - Misc. stuff * 5 5 * * 6 * Copyright 2006-2010 Wilmer van der Gaast <wilmer@gaast.net> 6 * Copyright 2006-2010 Wilmer van der Gaast <wilmer@gaast.net> 7 7 * * 8 8 * This program is free software; you can redistribute it and/or modify * … … 28 28 static unsigned int next_id = 1; 29 29 30 char *set_eval_priority( set_t *set, char *value)30 char *set_eval_priority(set_t *set, char *value) 31 31 { 32 32 account_t *acc = set->data; 33 33 int i; 34 35 if( sscanf( value, "%d", &i ) == 1 ) 36 { 34 35 if (sscanf(value, "%d", &i) == 1) { 37 36 /* Priority is a signed 8-bit integer, according to RFC 3921. */ 38 if ( i < -128 || i > 127 )37 if (i < -128 || i > 127) { 39 38 return SET_INVALID; 40 }41 else39 } 40 } else { 42 41 return SET_INVALID; 43 42 } 43 44 44 /* Only run this stuff if the account is online ATM, 45 45 and if the setting seems to be acceptable. */ 46 if( acc->ic ) 47 { 46 if (acc->ic) { 48 47 /* Although set_eval functions usually are very nice and 49 48 convenient, they have one disadvantage: If I would just … … 51 50 send the old setting because the set->value gets changed 52 51 after the (this) eval returns a non-NULL value. 53 52 54 53 So now I can choose between implementing post-set 55 54 functions next to evals, or just do this little hack: */ 56 57 g_free( set->value);58 set->value = g_strdup( value);59 55 56 g_free(set->value); 57 set->value = g_strdup(value); 58 60 59 /* (Yes, sorry, I prefer the hack. :-P) */ 61 62 presence_send_update( acc->ic);63 } 64 60 61 presence_send_update(acc->ic); 62 } 63 65 64 return value; 66 65 } 67 66 68 char *set_eval_tls( set_t *set, char *value)69 { 70 if ( g_strcasecmp( value, "try" ) == 0 )67 char *set_eval_tls(set_t *set, char *value) 68 { 69 if (g_strcasecmp(value, "try") == 0) { 71 70 return value; 72 else 73 return set_eval_bool( set, value ); 74 } 75 76 struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ) 71 } else { 72 return set_eval_bool(set, value); 73 } 74 } 75 76 struct xt_node *jabber_make_packet(char *name, char *type, char *to, struct xt_node *children) 77 77 { 78 78 struct xt_node *node; 79 80 node = xt_new_node( name, NULL, children ); 81 82 if( type ) 83 xt_add_attr( node, "type", type ); 84 if( to ) 85 xt_add_attr( node, "to", to ); 86 79 80 node = xt_new_node(name, NULL, children); 81 82 if (type) { 83 xt_add_attr(node, "type", type); 84 } 85 if (to) { 86 xt_add_attr(node, "to", to); 87 } 88 87 89 /* IQ packets should always have an ID, so let's generate one. It 88 90 might get overwritten by jabber_cache_add() if this packet has 89 91 to be saved until we receive a response. Cached packets get 90 92 slightly different IDs so we can recognize them. */ 91 if( strcmp( name, "iq" ) == 0 ) 92 { 93 char *id = g_strdup_printf( "%s%05x", JABBER_PACKET_ID, ( next_id++ ) & 0xfffff ); 94 xt_add_attr( node, "id", id ); 95 g_free( id ); 96 } 97 93 if (strcmp(name, "iq") == 0) { 94 char *id = g_strdup_printf("%s%05x", JABBER_PACKET_ID, (next_id++) & 0xfffff); 95 xt_add_attr(node, "id", id); 96 g_free(id); 97 } 98 98 99 return node; 99 100 } 100 101 101 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code)102 struct xt_node *jabber_make_error_packet(struct xt_node *orig, char *err_cond, char *err_type, char *err_code) 102 103 { 103 104 struct xt_node *node, *c; 104 105 char *to; 105 106 106 107 /* Create the "defined-condition" tag. */ 107 c = xt_new_node( err_cond, NULL, NULL);108 xt_add_attr( c, "xmlns", XMLNS_STANZA_ERROR);109 108 c = xt_new_node(err_cond, NULL, NULL); 109 xt_add_attr(c, "xmlns", XMLNS_STANZA_ERROR); 110 110 111 /* Put it in an <error> tag. */ 111 c = xt_new_node( "error", NULL, c);112 xt_add_attr( c, "type", err_type);113 112 c = xt_new_node("error", NULL, c); 113 xt_add_attr(c, "type", err_type); 114 114 115 /* Add the error code, if present */ 115 if (err_code) 116 xt_add_attr( c, "code", err_code ); 117 116 if (err_code) { 117 xt_add_attr(c, "code", err_code); 118 } 119 118 120 /* To make the actual error packet, we copy the original packet and 119 121 add our <error>/type="error" tag. Including the original packet 120 122 is recommended, so let's just do it. */ 121 node = xt_dup( orig);122 xt_add_child( node, c);123 xt_add_attr( node, "type", "error");124 123 node = xt_dup(orig); 124 xt_add_child(node, c); 125 xt_add_attr(node, "type", "error"); 126 125 127 /* Return to sender. */ 126 if( ( to = xt_find_attr( node, "from" ) ) ) 127 { 128 xt_add_attr( node, "to", to ); 129 xt_remove_attr( node, "from" ); 130 } 131 128 if ((to = xt_find_attr(node, "from"))) { 129 xt_add_attr(node, "to", to); 130 xt_remove_attr(node, "from"); 131 } 132 132 133 return node; 133 134 } … … 136 137 them when you receive the response. Use this BEFORE sending the packet so 137 138 it'll get a new id= tag, and do NOT free() the packet after sending it! */ 138 void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func)139 void jabber_cache_add(struct im_connection *ic, struct xt_node *node, jabber_cache_event func) 139 140 { 140 141 struct jabber_data *jd = ic->proto_data; 141 struct jabber_cache_entry *entry = g_new0( struct jabber_cache_entry, 1);142 struct jabber_cache_entry *entry = g_new0(struct jabber_cache_entry, 1); 142 143 md5_state_t id_hash; 143 144 md5_byte_t id_sum[16]; 144 145 char *id, *asc_hash; 145 146 next_id 147 146 147 next_id++; 148 148 149 id_hash = jd->cached_id_prefix; 149 md5_append( &id_hash, (md5_byte_t*) &next_id, sizeof( next_id ));150 md5_digest_keep( &id_hash, id_sum);151 asc_hash = base64_encode( id_sum, 12);152 153 id = g_strdup_printf( "%s%s", JABBER_CACHED_ID, asc_hash);154 xt_add_attr( node, "id", id);155 g_free( id);156 g_free( asc_hash);157 150 md5_append(&id_hash, (md5_byte_t *) &next_id, sizeof(next_id)); 151 md5_digest_keep(&id_hash, id_sum); 152 asc_hash = base64_encode(id_sum, 12); 153 154 id = g_strdup_printf("%s%s", JABBER_CACHED_ID, asc_hash); 155 xt_add_attr(node, "id", id); 156 g_free(id); 157 g_free(asc_hash); 158 158 159 entry->node = node; 159 160 entry->func = func; 160 entry->saved_at = time( NULL);161 g_hash_table_insert( jd->node_cache, xt_find_attr( node, "id" ), entry);162 } 163 164 void jabber_cache_entry_free( gpointer data)161 entry->saved_at = time(NULL); 162 g_hash_table_insert(jd->node_cache, xt_find_attr(node, "id"), entry); 163 } 164 165 void jabber_cache_entry_free(gpointer data) 165 166 { 166 167 struct jabber_cache_entry *entry = data; 167 168 xt_free_node( entry->node);169 g_free( entry);170 } 171 172 gboolean jabber_cache_clean_entry( gpointer key, gpointer entry, gpointer nullpointer);168 169 xt_free_node(entry->node); 170 g_free(entry); 171 } 172 173 gboolean jabber_cache_clean_entry(gpointer key, gpointer entry, gpointer nullpointer); 173 174 174 175 /* This one should be called from time to time (from keepalive, in this case) … … 177 178 node should be available in the cache for at least a minute (assuming the 178 179 function is indeed called every minute). */ 179 void jabber_cache_clean( struct im_connection *ic)180 void jabber_cache_clean(struct im_connection *ic) 180 181 { 181 182 struct jabber_data *jd = ic->proto_data; 182 time_t threshold = time( NULL) - JABBER_CACHE_MAX_AGE;183 184 g_hash_table_foreach_remove( jd->node_cache, jabber_cache_clean_entry, &threshold);185 } 186 187 gboolean jabber_cache_clean_entry( gpointer key, gpointer entry_, gpointer threshold_)183 time_t threshold = time(NULL) - JABBER_CACHE_MAX_AGE; 184 185 g_hash_table_foreach_remove(jd->node_cache, jabber_cache_clean_entry, &threshold); 186 } 187 188 gboolean jabber_cache_clean_entry(gpointer key, gpointer entry_, gpointer threshold_) 188 189 { 189 190 struct jabber_cache_entry *entry = entry_; 190 191 time_t *threshold = threshold_; 191 192 192 193 return entry->saved_at < *threshold; 193 194 } 194 195 195 xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node)196 xt_status jabber_cache_handle_packet(struct im_connection *ic, struct xt_node *node) 196 197 { 197 198 struct jabber_data *jd = ic->proto_data; 198 199 struct jabber_cache_entry *entry; 199 200 char *s; 200 201 if( ( s = xt_find_attr( node, "id" ) ) == NULL || 202 strncmp( s, JABBER_CACHED_ID, strlen( JABBER_CACHED_ID ) ) != 0 ) 203 { 201 202 if ((s = xt_find_attr(node, "id")) == NULL || 203 strncmp(s, JABBER_CACHED_ID, strlen(JABBER_CACHED_ID)) != 0) { 204 204 /* Silently ignore it, without an ID (or a non-cache 205 205 ID) we don't know how to handle the packet and we … … 207 207 return XT_HANDLED; 208 208 } 209 210 entry = g_hash_table_lookup( jd->node_cache, s ); 211 212 if( entry == NULL ) 213 { 209 210 entry = g_hash_table_lookup(jd->node_cache, s); 211 212 if (entry == NULL) { 214 213 /* 215 214 There's no longer an easy way to see if we generated this 216 215 one or someone else, and there's a ten-minute timeout anyway, 217 216 so meh. 218 217 219 218 imcb_log( ic, "Warning: Received %s-%s packet with unknown/expired ID %s!", 220 219 node->name, xt_find_attr( node, "type" ) ? : "(no type)", s ); 221 220 */ 222 } 223 else if( entry->func ) 224 { 225 return entry->func( ic, node, entry->node ); 226 } 227 221 } else if (entry->func) { 222 return entry->func(ic, node, entry->node); 223 } 224 228 225 return XT_HANDLED; 229 226 } … … 238 235 }; 239 236 240 const struct jabber_away_state *jabber_away_state_by_code( char *code)237 const struct jabber_away_state *jabber_away_state_by_code(char *code) 241 238 { 242 239 int i; 243 244 if ( code == NULL )240 241 if (code == NULL) { 245 242 return NULL; 246 247 for( i = 0; jabber_away_state_list[i].full_name; i ++ ) 248 if( g_strcasecmp( jabber_away_state_list[i].code, code ) == 0 ) 243 } 244 245 for (i = 0; jabber_away_state_list[i].full_name; i++) { 246 if (g_strcasecmp(jabber_away_state_list[i].code, code) == 0) { 249 247 return jabber_away_state_list + i; 250 248 } 249 } 250 251 251 return NULL; 252 252 } 253 253 254 const struct jabber_away_state *jabber_away_state_by_name( char *name)254 const struct jabber_away_state *jabber_away_state_by_name(char *name) 255 255 { 256 256 int i; 257 258 if ( name == NULL )257 258 if (name == NULL) { 259 259 return NULL; 260 261 for( i = 0; jabber_away_state_list[i].full_name; i ++ ) 262 if( g_strcasecmp( jabber_away_state_list[i].full_name, name ) == 0 ) 260 } 261 262 for (i = 0; jabber_away_state_list[i].full_name; i++) { 263 if (g_strcasecmp(jabber_away_state_list[i].full_name, name) == 0) { 263 264 return jabber_away_state_list + i; 264 265 } 266 } 267 265 268 return NULL; 266 269 } 267 270 268 struct jabber_buddy_ask_data 269 { 271 struct jabber_buddy_ask_data { 270 272 struct im_connection *ic; 271 273 char *handle; … … 273 275 }; 274 276 275 static void jabber_buddy_ask_yes( void *data)277 static void jabber_buddy_ask_yes(void *data) 276 278 { 277 279 struct jabber_buddy_ask_data *bla = data; 278 279 presence_send_request( bla->ic, bla->handle, "subscribed");280 281 imcb_ask_add( bla->ic, bla->handle, NULL);282 283 g_free( bla->handle);284 g_free( bla);285 } 286 287 static void jabber_buddy_ask_no( void *data)280 281 presence_send_request(bla->ic, bla->handle, "subscribed"); 282 283 imcb_ask_add(bla->ic, bla->handle, NULL); 284 285 g_free(bla->handle); 286 g_free(bla); 287 } 288 289 static void jabber_buddy_ask_no(void *data) 288 290 { 289 291 struct jabber_buddy_ask_data *bla = data; 290 291 presence_send_request( bla->ic, bla->handle, "unsubscribed");292 293 g_free( bla->handle);294 g_free( bla);295 } 296 297 void jabber_buddy_ask( struct im_connection *ic, char *handle)298 { 299 struct jabber_buddy_ask_data *bla = g_new0( struct jabber_buddy_ask_data, 1);292 293 presence_send_request(bla->ic, bla->handle, "unsubscribed"); 294 295 g_free(bla->handle); 296 g_free(bla); 297 } 298 299 void jabber_buddy_ask(struct im_connection *ic, char *handle) 300 { 301 struct jabber_buddy_ask_data *bla = g_new0(struct jabber_buddy_ask_data, 1); 300 302 char *buf; 301 303 302 304 bla->ic = ic; 303 bla->handle = g_strdup( handle);304 305 buf = g_strdup_printf( "The user %s wants to add you to his/her buddy list.", handle);306 imcb_ask( ic, buf, bla, jabber_buddy_ask_yes, jabber_buddy_ask_no);307 g_free( buf);305 bla->handle = g_strdup(handle); 306 307 buf = g_strdup_printf("The user %s wants to add you to his/her buddy list.", handle); 308 imcb_ask(ic, buf, bla, jabber_buddy_ask_yes, jabber_buddy_ask_no); 309 g_free(buf); 308 310 } 309 311 310 312 /* Compares just the bare portions of two Jabber IDs. */ 311 int jabber_compare_jid( const char *jid1, const char *jid2)313 int jabber_compare_jid(const char *jid1, const char *jid2) 312 314 { 313 315 int i; 314 315 for( i = 0; ; i ++ ) 316 { 317 if( jid1[i] == '\0' || jid1[i] == '/' || jid2[i] == '\0' || jid2[i] == '/' ) 318 { 319 if( ( jid1[i] == '\0' || jid1[i] == '/' ) && ( jid2[i] == '\0' || jid2[i] == '/' ) ) 316 317 for (i = 0;; i++) { 318 if (jid1[i] == '\0' || jid1[i] == '/' || jid2[i] == '\0' || jid2[i] == '/') { 319 if ((jid1[i] == '\0' || jid1[i] == '/') && (jid2[i] == '\0' || jid2[i] == '/')) { 320 320 break; 321 } 321 322 return FALSE; 322 323 } 323 if( g_ascii_tolower( jid1[i] ) != g_ascii_tolower( jid2[i] ) ) 324 { 324 if (g_ascii_tolower(jid1[i]) != g_ascii_tolower(jid2[i])) { 325 325 return FALSE; 326 326 } 327 327 } 328 328 329 329 return TRUE; 330 330 } … … 332 332 /* The /resource part is case sensitive. This stops once we see a slash. 333 333 Returns a new string. Don't leak it! */ 334 char *jabber_normalize( const char *orig)334 char *jabber_normalize(const char *orig) 335 335 { 336 336 char *lower, *new, *s; 337 337 338 if ( ! ( s = strchr( orig, '/' ) ) ) 339 return g_utf8_strdown( orig, -1 ); 340 341 lower = g_utf8_strdown( orig, (s - orig) ); /* stop in s */ 342 new = g_strconcat( lower, s, NULL ); 343 g_free( lower ); 338 if (!(s = strchr(orig, '/'))) { 339 return g_utf8_strdown(orig, -1); 340 } 341 342 lower = g_utf8_strdown(orig, (s - orig)); /* stop in s */ 343 new = g_strconcat(lower, s, NULL); 344 g_free(lower); 344 345 return new; 345 346 } … … 347 348 /* Similar to jabber_normalize, but works with addresses in the form 348 349 * resource=chatroom@example.com */ 349 char *jabber_normalize_ext( const char *orig)350 char *jabber_normalize_ext(const char *orig) 350 351 { 351 352 char *lower, *new, *s; 352 353 353 if ( ! ( s = strchr( orig, '=' ) ) ) 354 return g_utf8_strdown( orig, -1 ); 355 356 lower = g_utf8_strdown( s, -1 ); /* start in s */ 354 if (!(s = strchr(orig, '='))) { 355 return g_utf8_strdown(orig, -1); 356 } 357 358 lower = g_utf8_strdown(s, -1); /* start in s */ 357 359 358 360 *s = 0; 359 new = g_strconcat( orig, lower, NULL);361 new = g_strconcat(orig, lower, NULL); 360 362 *s = '='; 361 363 362 g_free( lower);364 g_free(lower); 363 365 return new; 364 366 } … … 369 371 to deal with that properly. Set their ->resource property to NULL. Do *NOT* 370 372 allow to mix this stuff, though... */ 371 struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid_)373 struct jabber_buddy *jabber_buddy_add(struct im_connection *ic, char *full_jid_) 372 374 { 373 375 struct jabber_data *jd = ic->proto_data; 374 376 struct jabber_buddy *bud, *new, *bi; 375 377 char *s, *full_jid; 376 377 full_jid = jabber_normalize( full_jid_);378 379 if ( ( s = strchr( full_jid, '/' ) ) )378 379 full_jid = jabber_normalize(full_jid_); 380 381 if ((s = strchr(full_jid, '/'))) { 380 382 *s = 0; 381 382 new = g_new0( struct jabber_buddy, 1 ); 383 384 if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) 385 {383 } 384 385 new = g_new0(struct jabber_buddy, 1); 386 387 if ((bud = g_hash_table_lookup(jd->buddies, full_jid))) { 386 388 /* The first entry is always a bare JID. If there are more, we 387 389 should ignore the first one here. */ 388 if ( bud->next )390 if (bud->next) { 389 391 bud = bud->next; 390 392 } 393 391 394 /* If this is a transport buddy or whatever, it can't have more 392 395 than one instance, so this is always wrong: */ 393 if( s == NULL || bud->resource == NULL ) 394 { 395 if( s ) *s = '/'; 396 g_free( new ); 397 g_free( full_jid ); 396 if (s == NULL || bud->resource == NULL) { 397 if (s) { 398 *s = '/'; 399 } 400 g_free(new); 401 g_free(full_jid); 398 402 return NULL; 399 403 } 400 404 401 405 new->bare_jid = bud->bare_jid; 402 406 403 407 /* We already have another resource for this buddy, add the 404 408 new one to the list. */ 405 for( bi = bud; bi; bi = bi->next ) 406 { 409 for (bi = bud; bi; bi = bi->next) { 407 410 /* Check for dupes. */ 408 if( strcmp( bi->resource, s + 1 ) == 0 ) 409 { 411 if (strcmp(bi->resource, s + 1) == 0) { 410 412 *s = '/'; 411 g_free( new);412 g_free( full_jid);413 g_free(new); 414 g_free(full_jid); 413 415 return NULL; 414 416 } 415 417 /* Append the new item to the list. */ 416 else if( bi->next == NULL ) 417 { 418 else if (bi->next == NULL) { 418 419 bi->next = new; 419 420 break; 420 421 } 421 422 } 422 } 423 else 424 { 425 new->full_jid = new->bare_jid = g_strdup( full_jid ); 426 g_hash_table_insert( jd->buddies, new->bare_jid, new ); 427 428 if( s ) 429 { 430 new->next = g_new0( struct jabber_buddy, 1 ); 423 } else { 424 new->full_jid = new->bare_jid = g_strdup(full_jid); 425 g_hash_table_insert(jd->buddies, new->bare_jid, new); 426 427 if (s) { 428 new->next = g_new0(struct jabber_buddy, 1); 431 429 new->next->bare_jid = new->bare_jid; 432 430 new = new->next; 433 431 } 434 432 } 435 436 if( s ) 437 { 433 434 if (s) { 438 435 *s = '/'; 439 436 new->full_jid = full_jid; 440 new->resource = strchr( new->full_jid, '/' ) + 1; 441 } 442 else 443 { 437 new->resource = strchr(new->full_jid, '/') + 1; 438 } else { 444 439 /* Let's waste some more bytes of RAM instead of to make 445 440 memory management a total disaster here. And it saves … … 447 442 new->full_jid = full_jid; 448 443 } 449 444 450 445 return new; 451 446 } … … 454 449 asked for a bare JID, it uses the "resource_select" setting to see which 455 450 resource to pick. */ 456 struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags)451 struct jabber_buddy *jabber_buddy_by_jid(struct im_connection *ic, char *jid_, get_buddy_flags_t flags) 457 452 { 458 453 struct jabber_data *jd = ic->proto_data; 459 454 struct jabber_buddy *bud, *head; 460 455 char *s, *jid; 461 462 jid = jabber_normalize( jid_ ); 463 464 if( ( s = strchr( jid, '/' ) ) ) 465 { 456 457 jid = jabber_normalize(jid_); 458 459 if ((s = strchr(jid, '/'))) { 466 460 int bare_exists = 0; 467 461 468 462 *s = 0; 469 if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) 470 { 463 if ((bud = g_hash_table_lookup(jd->buddies, jid))) { 471 464 bare_exists = 1; 472 473 if ( bud->next )465 466 if (bud->next) { 474 467 bud = bud->next; 475 468 } 469 476 470 /* Just return the first one for this bare JID. */ 477 if( flags & GET_BUDDY_FIRST ) 478 { 471 if (flags & GET_BUDDY_FIRST) { 479 472 *s = '/'; 480 g_free( jid);473 g_free(jid); 481 474 return bud; 482 475 } 483 476 484 477 /* Is this one of those no-resource buddies? */ 485 if( bud->resource == NULL ) 486 { 478 if (bud->resource == NULL) { 487 479 *s = '/'; 488 g_free( jid);480 g_free(jid); 489 481 return NULL; 490 482 } 491 483 492 484 /* See if there's an exact match. */ 493 for ( ; bud; bud = bud->next )494 if ( strcmp( bud->resource, s + 1 ) == 0 )485 for (; bud; bud = bud->next) { 486 if (strcmp(bud->resource, s + 1) == 0) { 495 487 break; 496 } 497 498 if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && 499 ( bare_exists || bee_user_by_handle( ic->bee, ic, jid ) ) ) 500 { 488 } 489 } 490 } 491 492 if (bud == NULL && (flags & GET_BUDDY_CREAT) && 493 (bare_exists || bee_user_by_handle(ic->bee, ic, jid))) { 501 494 *s = '/'; 502 bud = jabber_buddy_add( ic, jid);503 } 504 505 g_free( jid);495 bud = jabber_buddy_add(ic, jid); 496 } 497 498 g_free(jid); 506 499 return bud; 507 } 508 else 509 { 500 } else { 510 501 struct jabber_buddy *best_prio, *best_time; 511 502 char *set; 512 513 head = g_hash_table_lookup( jd->buddies, jid);514 bud = ( head && head->next) ? head->next : head;515 516 g_free( jid);517 518 if ( bud == NULL )503 504 head = g_hash_table_lookup(jd->buddies, jid); 505 bud = (head && head->next) ? head->next : head; 506 507 g_free(jid); 508 509 if (bud == NULL) { 519 510 /* No match. Create it now? */ 520 return ( ( flags & GET_BUDDY_CREAT) &&521 bee_user_by_handle( ic->bee, ic, jid_ )) ?522 jabber_buddy_add( ic, jid_) : NULL;523 else if( bud->resource && ( flags & GET_BUDDY_EXACT ) )511 return ((flags & GET_BUDDY_CREAT) && 512 bee_user_by_handle(ic->bee, ic, jid_)) ? 513 jabber_buddy_add(ic, jid_) : NULL; 514 } else if (bud->resource && (flags & GET_BUDDY_EXACT)) { 524 515 /* We want an exact match, so in thise case there shouldn't be a /resource. */ 525 516 return NULL; 526 else if( bud->resource == NULL || bud->next == NULL )517 } else if (bud->resource == NULL || bud->next == NULL) { 527 518 /* No need for selection if there's only one option. */ 528 519 return bud; 529 else if( flags & GET_BUDDY_FIRST )520 } else if (flags & GET_BUDDY_FIRST) { 530 521 /* Looks like the caller doesn't care about details. */ 531 522 return bud; 532 else if( flags & GET_BUDDY_BARE )523 } else if (flags & GET_BUDDY_BARE) { 533 524 return head; 534 525 } 526 535 527 best_prio = best_time = bud; 536 for( ; bud; bud = bud->next ) 537 { 538 if( bud->priority > best_prio->priority ) 528 for (; bud; bud = bud->next) { 529 if (bud->priority > best_prio->priority) { 539 530 best_prio = bud; 540 if( bud->last_msg > best_time->last_msg ) 531 } 532 if (bud->last_msg > best_time->last_msg) { 541 533 best_time = bud; 542 } 543 544 if( ( set = set_getstr( &ic->acc->set, "resource_select" ) ) == NULL ) 534 } 535 } 536 537 if ((set = set_getstr(&ic->acc->set, "resource_select")) == NULL) { 545 538 return NULL; 546 else if( strcmp( set, "priority" ) == 0 )539 } else if (strcmp(set, "priority") == 0) { 547 540 return best_prio; 548 else if( flags & GET_BUDDY_BARE_OK ) /* && strcmp( set, "activity" ) == 0 */ 549 { 550 if( best_time->last_msg + set_getint( &ic->acc->set, "activity_timeout" ) >= time( NULL ) ) 541 } else if (flags & GET_BUDDY_BARE_OK) { /* && strcmp( set, "activity" ) == 0 */ 542 if (best_time->last_msg + set_getint(&ic->acc->set, "activity_timeout") >= time(NULL)) { 551 543 return best_time; 552 else544 } else { 553 545 return head; 554 }555 else546 } 547 } else { 556 548 return best_time; 549 } 557 550 } 558 551 } … … 565 558 replacing the / with a =. But there should be some stripping (@s are 566 559 allowed in Jabber nicks...). */ 567 struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags)560 struct jabber_buddy *jabber_buddy_by_ext_jid(struct im_connection *ic, char *jid_, get_buddy_flags_t flags) 568 561 { 569 562 struct jabber_buddy *bud; 570 563 char *s, *jid; 571 572 jid = jabber_normalize_ext( jid_);573 574 if ( ( s = strchr( jid, '=' ) ) == NULL )564 565 jid = jabber_normalize_ext(jid_); 566 567 if ((s = strchr(jid, '=')) == NULL) { 575 568 return NULL; 576 577 for( bud = jabber_buddy_by_jid( ic, s + 1, GET_BUDDY_FIRST ); bud; bud = bud->next ) 578 {569 } 570 571 for (bud = jabber_buddy_by_jid(ic, s + 1, GET_BUDDY_FIRST); bud; bud = bud->next) { 579 572 /* Hmmm, could happen if not all people in the chat are anonymized? */ 580 if ( bud->ext_jid == NULL )573 if (bud->ext_jid == NULL) { 581 574 continue; 582 583 if( strcmp( bud->ext_jid, jid ) == 0 ) 575 } 576 577 if (strcmp(bud->ext_jid, jid) == 0) { 584 578 break; 585 } 586 587 g_free( jid ); 588 579 } 580 } 581 582 g_free(jid); 583 589 584 return bud; 590 585 } … … 593 588 off-line (because (s)he can still be online from a different location. 594 589 XXX: See above, we should accept bare JIDs too... */ 595 int jabber_buddy_remove( struct im_connection *ic, char *full_jid_)590 int jabber_buddy_remove(struct im_connection *ic, char *full_jid_) 596 591 { 597 592 struct jabber_data *jd = ic->proto_data; 598 593 struct jabber_buddy *bud, *prev = NULL, *bi; 599 594 char *s, *full_jid; 600 601 full_jid = jabber_normalize( full_jid_);602 603 if ( ( s = strchr( full_jid, '/' ) ) )595 596 full_jid = jabber_normalize(full_jid_); 597 598 if ((s = strchr(full_jid, '/'))) { 604 599 *s = 0; 605 606 if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) 607 { 608 if( bud->next ) 609 bud = (prev=bud)->next; 610 600 } 601 602 if ((bud = g_hash_table_lookup(jd->buddies, full_jid))) { 603 if (bud->next) { 604 bud = (prev = bud)->next; 605 } 606 611 607 /* If there's only one item in the list (and if the resource 612 608 matches), removing it is simple. (And the hash reference 613 609 should be removed too!) */ 614 if( bud->next == NULL && 615 ( ( s == NULL && bud->resource == NULL ) || 616 ( bud->resource && s && strcmp( bud->resource, s + 1 ) == 0 ) ) ) 617 { 618 int st = jabber_buddy_remove_bare( ic, full_jid ); 619 g_free( full_jid ); 610 if (bud->next == NULL && 611 ((s == NULL && bud->resource == NULL) || 612 (bud->resource && s && strcmp(bud->resource, s + 1) == 0))) { 613 int st = jabber_buddy_remove_bare(ic, full_jid); 614 g_free(full_jid); 620 615 return st; 621 } 622 else if( s == NULL || bud->resource == NULL ) 623 { 616 } else if (s == NULL || bud->resource == NULL) { 624 617 /* Tried to remove a bare JID while this JID does seem 625 618 to have resources... (Or the opposite.) *sigh* */ 626 g_free( full_jid);619 g_free(full_jid); 627 620 return 0; 628 } 629 else 630 { 631 for( bi = bud; bi; bi = (prev=bi)->next ) 632 if( strcmp( bi->resource, s + 1 ) == 0 ) 621 } else { 622 for (bi = bud; bi; bi = (prev = bi)->next) { 623 if (strcmp(bi->resource, s + 1) == 0) { 633 624 break; 634 635 g_free( full_jid ); 636 637 if( bi ) 638 { 639 if( prev ) 625 } 626 } 627 628 g_free(full_jid); 629 630 if (bi) { 631 if (prev) { 640 632 prev->next = bi->next; 641 else633 } else { 642 634 /* Don't think this should ever happen anymore. */ 643 g_hash_table_replace( jd->buddies, bi->bare_jid, bi->next ); 644 645 g_free( bi->ext_jid ); 646 g_free( bi->full_jid ); 647 g_free( bi->away_message ); 648 g_free( bi ); 649 635 g_hash_table_replace(jd->buddies, bi->bare_jid, bi->next); 636 } 637 638 g_free(bi->ext_jid); 639 g_free(bi->full_jid); 640 g_free(bi->away_message); 641 g_free(bi); 642 650 643 return 1; 651 } 652 else 653 { 644 } else { 654 645 return 0; 655 646 } 656 647 } 657 } 658 else 659 { 660 g_free( full_jid ); 648 } else { 649 g_free(full_jid); 661 650 return 0; 662 651 } … … 666 655 specified bare JID. Use this when removing someone from the contact 667 656 list, for example. */ 668 int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid)657 int jabber_buddy_remove_bare(struct im_connection *ic, char *bare_jid) 669 658 { 670 659 struct jabber_data *jd = ic->proto_data; 671 660 struct jabber_buddy *bud, *next; 672 673 if ( strchr( bare_jid, '/' ) )661 662 if (strchr(bare_jid, '/')) { 674 663 return 0; 675 676 if( ( bud = jabber_buddy_by_jid( ic, bare_jid, GET_BUDDY_FIRST ) ) ) 677 {664 } 665 666 if ((bud = jabber_buddy_by_jid(ic, bare_jid, GET_BUDDY_FIRST))) { 678 667 /* Most important: Remove the hash reference. We don't know 679 668 this buddy anymore. */ 680 g_hash_table_remove( jd->buddies, bud->bare_jid);681 g_free( bud->bare_jid);682 669 g_hash_table_remove(jd->buddies, bud->bare_jid); 670 g_free(bud->bare_jid); 671 683 672 /* Deallocate the linked list of resources. */ 684 while( bud ) 685 { 673 while (bud) { 686 674 /* ext_jid && anonymous means that this buddy is 687 675 specific to one groupchat (the one we're 688 676 currently cleaning up) so it can be deleted 689 677 completely. */ 690 if( bud->ext_jid && bud->flags & JBFLAG_IS_ANONYMOUS ) 691 imcb_remove_buddy( ic, bud->ext_jid, NULL ); 692 678 if (bud->ext_jid && bud->flags & JBFLAG_IS_ANONYMOUS) { 679 imcb_remove_buddy(ic, bud->ext_jid, NULL); 680 } 681 693 682 next = bud->next; 694 g_free( bud->ext_jid);695 g_free( bud->full_jid);696 g_free( bud->away_message);697 g_free( bud);683 g_free(bud->ext_jid); 684 g_free(bud->full_jid); 685 g_free(bud->away_message); 686 g_free(bud); 698 687 bud = next; 699 688 } 700 689 701 690 return 1; 702 } 703 else 704 { 691 } else { 705 692 return 0; 706 693 } 707 694 } 708 695 709 static gboolean jabber_buddy_remove_all_cb( gpointer key, gpointer value, gpointer data)696 static gboolean jabber_buddy_remove_all_cb(gpointer key, gpointer value, gpointer data) 710 697 { 711 698 struct jabber_buddy *bud, *next; 712 699 713 700 bud = value; 714 if ( bud->bare_jid != bud->full_jid )715 g_free( bud->bare_jid);716 while( bud )717 {701 if (bud->bare_jid != bud->full_jid) { 702 g_free(bud->bare_jid); 703 } 704 while (bud) { 718 705 next = bud->next; 719 g_free( bud->ext_jid);720 g_free( bud->full_jid);721 g_free( bud->away_message);722 g_free( bud);706 g_free(bud->ext_jid); 707 g_free(bud->full_jid); 708 g_free(bud->away_message); 709 g_free(bud); 723 710 bud = next; 724 711 } 725 712 726 713 return TRUE; 727 714 } 728 715 729 void jabber_buddy_remove_all( struct im_connection *ic)716 void jabber_buddy_remove_all(struct im_connection *ic) 730 717 { 731 718 struct jabber_data *jd = ic->proto_data; 732 733 g_hash_table_foreach_remove( jd->buddies, jabber_buddy_remove_all_cb, NULL);734 g_hash_table_destroy( jd->buddies);735 } 736 737 time_t jabber_get_timestamp( struct xt_node *xt)719 720 g_hash_table_foreach_remove(jd->buddies, jabber_buddy_remove_all_cb, NULL); 721 g_hash_table_destroy(jd->buddies); 722 } 723 724 time_t jabber_get_timestamp(struct xt_node *xt) 738 725 { 739 726 struct xt_node *c; … … 744 731 745 732 /* XEP-0091 has <x> */ 746 c = xt_find_node_by_attr( xt->children, "x", "xmlns", XMLNS_DELAY_OLD);747 748 if ( !c || !( s = xt_find_attr( c, "stamp" ) )) {733 c = xt_find_node_by_attr(xt->children, "x", "xmlns", XMLNS_DELAY_OLD); 734 735 if (!c || !(s = xt_find_attr(c, "stamp"))) { 749 736 is_old = FALSE; 750 737 751 738 /* XEP-0203 has <delay> */ 752 c = xt_find_node_by_attr( xt->children, "delay", "xmlns", XMLNS_DELAY);753 if ( !c || !( s = xt_find_attr( c, "stamp" ) )) {739 c = xt_find_node_by_attr(xt->children, "delay", "xmlns", XMLNS_DELAY); 740 if (!c || !(s = xt_find_attr(c, "stamp"))) { 754 741 return 0; 755 742 } 756 743 } 757 758 memset( &tp, 0, sizeof( tp ));744 745 memset(&tp, 0, sizeof(tp)); 759 746 760 747 /* The other main difference between XEPs is the timestamp format */ 761 748 format = (is_old) ? "%4d%2d%2dT%2d:%2d:%2d" : "%4d-%2d-%2dT%2d:%2d:%2dZ"; 762 749 763 if ( sscanf(s, format, &tp.tm_year, &tp.tm_mon, &tp.tm_mday,764 &tp.tm_hour, &tp.tm_min, &tp.tm_sec ) != 6 )750 if (sscanf(s, format, &tp.tm_year, &tp.tm_mon, &tp.tm_mday, 751 &tp.tm_hour, &tp.tm_min, &tp.tm_sec) != 6) { 765 752 return 0; 766 753 } 754 767 755 tp.tm_year -= 1900; 768 tp.tm_mon 769 770 return mktime_utc( &tp);771 } 772 773 struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns)756 tp.tm_mon--; 757 758 return mktime_utc(&tp); 759 } 760 761 struct jabber_error *jabber_error_parse(struct xt_node *node, char *xmlns) 774 762 { 775 763 struct jabber_error *err; 776 764 struct xt_node *c; 777 765 char *s; 778 779 if ( node == NULL )766 767 if (node == NULL) { 780 768 return NULL; 781 782 err = g_new0( struct jabber_error, 1 ); 783 err ->type = xt_find_attr( node, "type");784 785 for( c = node->children; c; c = c->next ) 786 {787 if ( !( s = xt_find_attr( c, "xmlns" )) ||788 strcmp( s, xmlns ) != 0 )769 } 770 771 err = g_new0(struct jabber_error, 1); 772 err->type = xt_find_attr(node, "type"); 773 774 for (c = node->children; c; c = c->next) { 775 if (!(s = xt_find_attr(c, "xmlns")) || 776 strcmp(s, xmlns) != 0) { 789 777 continue; 790 791 if( strcmp( c->name, "text" ) != 0 ) 792 {778 } 779 780 if (strcmp(c->name, "text") != 0) { 793 781 err->code = c->name; 794 782 } 795 783 /* Only use the text if it doesn't have an xml:lang attribute, 796 784 if it's empty or if it's set to something English. */ 797 else if( !( s = xt_find_attr( c, "xml:lang" ) ) || 798 !*s || strncmp( s, "en", 2 ) == 0 ) 799 { 785 else if (!(s = xt_find_attr(c, "xml:lang")) || 786 !*s || strncmp(s, "en", 2) == 0) { 800 787 err->text = c->text; 801 788 } 802 789 } 803 790 804 791 return err; 805 792 } 806 793 807 void jabber_error_free( struct jabber_error *err)808 { 809 g_free( err);810 } 811 812 gboolean jabber_set_me( struct im_connection *ic, const char *me)794 void jabber_error_free(struct jabber_error *err) 795 { 796 g_free(err); 797 } 798 799 gboolean jabber_set_me(struct im_connection *ic, const char *me) 813 800 { 814 801 struct jabber_data *jd = ic->proto_data; 815 816 if ( strchr( me, '@' ) == NULL )802 803 if (strchr(me, '@') == NULL) { 817 804 return FALSE; 818 819 g_free( jd->username ); 820 g_free( jd->me ); 821 822 jd->me = jabber_normalize( me ); 823 jd->server = strchr( jd->me, '@' ); 824 jd->username = g_strndup( jd->me, jd->server - jd->me ); 825 jd->server ++; 805 } 806 807 g_free(jd->username); 808 g_free(jd->me); 809 810 jd->me = jabber_normalize(me); 811 jd->server = strchr(jd->me, '@'); 812 jd->username = g_strndup(jd->me, jd->server - jd->me); 813 jd->server++; 826 814 827 815 /* Set the "internal" account username, for groupchats */ 828 g_free( jd->internal_jid);829 jd->internal_jid = g_strdup( jd->me);830 816 g_free(jd->internal_jid); 817 jd->internal_jid = g_strdup(jd->me); 818 831 819 return TRUE; 832 820 } -
protocols/jabber/message.c
raf359b4 r5ebff60 24 24 #include "jabber.h" 25 25 26 xt_status jabber_pkt_message( struct xt_node *node, gpointer data)26 xt_status jabber_pkt_message(struct xt_node *node, gpointer data) 27 27 { 28 28 struct im_connection *ic = data; 29 char *from = xt_find_attr( node, "from");30 char *type = xt_find_attr( node, "type");31 char *id = xt_find_attr( node, "id");32 struct xt_node *body = xt_find_node( node->children, "body"), *c;33 struct xt_node *request = xt_find_node( node->children, "request");29 char *from = xt_find_attr(node, "from"); 30 char *type = xt_find_attr(node, "type"); 31 char *id = xt_find_attr(node, "id"); 32 struct xt_node *body = xt_find_node(node->children, "body"), *c; 33 struct xt_node *request = xt_find_node(node->children, "request"); 34 34 struct jabber_buddy *bud = NULL; 35 35 char *s, *room = NULL, *reason = NULL; 36 37 if ( !from )36 37 if (!from) { 38 38 return XT_HANDLED; /* Consider this packet corrupted. */ 39 39 40 if( request && id )41 {40 } 41 if (request && id) { 42 42 /* Send a message receipt (XEP-0184), looking like this: 43 43 * <message … … 48 48 * </message> */ 49 49 struct xt_node *received, *receipt; 50 51 received = xt_new_node( "received", NULL, NULL );52 xt_add_attr( received, "xmlns", XMLNS_RECEIPTS );53 xt_add_attr( received, "id", id );54 receipt = jabber_make_packet( "message", NULL, from, received );55 50 56 jabber_write_packet( ic, receipt ); 57 xt_free_node( receipt ); 51 received = xt_new_node("received", NULL, NULL); 52 xt_add_attr(received, "xmlns", XMLNS_RECEIPTS); 53 xt_add_attr(received, "id", id); 54 receipt = jabber_make_packet("message", NULL, from, received); 55 56 jabber_write_packet(ic, receipt); 57 xt_free_node(receipt); 58 58 } 59 60 bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ); 61 62 if( type && strcmp( type, "error" ) == 0 ) 63 { 59 60 bud = jabber_buddy_by_jid(ic, from, GET_BUDDY_EXACT); 61 62 if (type && strcmp(type, "error") == 0) { 64 63 /* Handle type=error packet. */ 65 } 66 else if( type && from && strcmp( type, "groupchat" ) == 0 ) 67 { 68 jabber_chat_pkt_message( ic, bud, node ); 69 } 70 else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */ 71 { 72 GString *fullmsg = g_string_new( "" ); 64 } else if (type && from && strcmp(type, "groupchat") == 0) { 65 jabber_chat_pkt_message(ic, bud, node); 66 } else { /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */ 67 GString *fullmsg = g_string_new(""); 73 68 74 for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) 75 { 76 char *ns = xt_find_attr( c, "xmlns" ); 69 for (c = node->children; (c = xt_find_node(c, "x")); c = c->next) { 70 char *ns = xt_find_attr(c, "xmlns"); 77 71 struct xt_node *inv; 78 79 if( ns && strcmp( ns, XMLNS_MUC_USER ) == 0 && 80 ( inv = xt_find_node( c->children, "invite" ) ) ) 81 { 72 73 if (ns && strcmp(ns, XMLNS_MUC_USER) == 0 && 74 (inv = xt_find_node(c->children, "invite"))) { 82 75 /* This is an invitation. Set some vars which 83 76 will be passed to imcb_chat_invite() below. */ 84 77 room = from; 85 if ( ( from = xt_find_attr( inv, "from" ) ) == NULL )78 if ((from = xt_find_attr(inv, "from")) == NULL) { 86 79 from = room; 87 if( ( inv = xt_find_node( inv->children, "reason" ) ) && inv->text_len > 0 ) 80 } 81 if ((inv = xt_find_node(inv->children, "reason")) && inv->text_len > 0) { 88 82 reason = inv->text; 83 } 89 84 } 90 85 } 91 92 if( ( s = strchr( from, '/' ) ) ) 93 { 94 if( bud ) 95 { 96 bud->last_msg = time( NULL ); 86 87 if ((s = strchr(from, '/'))) { 88 if (bud) { 89 bud->last_msg = time(NULL); 97 90 from = bud->ext_jid ? bud->ext_jid : bud->bare_jid; 98 } 99 else 91 } else { 100 92 *s = 0; /* We need to generate a bare JID now. */ 101 }102 103 if( type && strcmp( type, "headline" ) == 0 )104 {105 if( ( c = xt_find_node( node->children, "subject" ) ) && c->text_len > 0 )106 g_string_append_printf( fullmsg, "Headline: %s\n", c->text );107 108 /* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */109 for( c = node->children; c; c = c->next )110 {111 struct xt_node *url;112 113 if( ( url = xt_find_node( c->children, "url" ) ) && url->text_len > 0 )114 g_string_append_printf( fullmsg, "URL: %s\n", url->text );115 93 } 116 94 } 117 else if( ( c = xt_find_node( node->children, "subject" ) ) && c->text_len > 0 && 118 ( !bud || !( bud->flags & JBFLAG_HIDE_SUBJECT ) ) ) 119 { 120 g_string_append_printf( fullmsg, "<< \002BitlBee\002 - Message with subject: %s >>\n", c->text ); 121 if( bud ) 95 96 if (type && strcmp(type, "headline") == 0) { 97 if ((c = xt_find_node(node->children, "subject")) && c->text_len > 0) { 98 g_string_append_printf(fullmsg, "Headline: %s\n", c->text); 99 } 100 101 /* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */ 102 for (c = node->children; c; c = c->next) { 103 struct xt_node *url; 104 105 if ((url = xt_find_node(c->children, "url")) && url->text_len > 0) { 106 g_string_append_printf(fullmsg, "URL: %s\n", url->text); 107 } 108 } 109 } else if ((c = xt_find_node(node->children, "subject")) && c->text_len > 0 && 110 (!bud || !(bud->flags & JBFLAG_HIDE_SUBJECT))) { 111 g_string_append_printf(fullmsg, "<< \002BitlBee\002 - Message with subject: %s >>\n", c->text); 112 if (bud) { 122 113 bud->flags |= JBFLAG_HIDE_SUBJECT; 123 } 124 else if( bud && !c ) 125 { 114 } 115 } else if (bud && !c) { 126 116 /* Yeah, possibly we're hiding changes to this field now. But nobody uses 127 117 this for anything useful anyway, except GMail when people reply to an … … 130 120 bud->flags &= ~JBFLAG_HIDE_SUBJECT; 131 121 } 132 133 if( body && body->text_len > 0 ) /* Could be just a typing notification. */ 134 fullmsg = g_string_append( fullmsg, body->text ); 135 136 if( fullmsg->len > 0 ) 137 imcb_buddy_msg( ic, from, fullmsg->str, 138 0, jabber_get_timestamp( node ) ); 139 if( room ) 140 imcb_chat_invite( ic, room, from, reason ); 141 142 g_string_free( fullmsg, TRUE ); 143 122 123 if (body && body->text_len > 0) { /* Could be just a typing notification. */ 124 fullmsg = g_string_append(fullmsg, body->text); 125 } 126 127 if (fullmsg->len > 0) { 128 imcb_buddy_msg(ic, from, fullmsg->str, 129 0, jabber_get_timestamp(node)); 130 } 131 if (room) { 132 imcb_chat_invite(ic, room, from, reason); 133 } 134 135 g_string_free(fullmsg, TRUE); 136 144 137 /* Handling of incoming typing notifications. */ 145 if( bud == NULL ) 146 { 138 if (bud == NULL) { 147 139 /* Can't handle these for unknown buddies. */ 148 } 149 else if( xt_find_node( node->children, "composing" ) ) 150 { 140 } else if (xt_find_node(node->children, "composing")) { 151 141 bud->flags |= JBFLAG_DOES_XEP85; 152 imcb_buddy_typing( ic, from, OPT_TYPING);142 imcb_buddy_typing(ic, from, OPT_TYPING); 153 143 } 154 144 /* No need to send a "stopped typing" signal when there's a message. */ 155 else if( xt_find_node( node->children, "active" ) && ( body == NULL ) ) 156 { 145 else if (xt_find_node(node->children, "active") && (body == NULL)) { 157 146 bud->flags |= JBFLAG_DOES_XEP85; 158 imcb_buddy_typing( ic, from, 0 ); 147 imcb_buddy_typing(ic, from, 0); 148 } else if (xt_find_node(node->children, "paused")) { 149 bud->flags |= JBFLAG_DOES_XEP85; 150 imcb_buddy_typing(ic, from, OPT_THINKING); 159 151 } 160 else if( xt_find_node( node->children, "paused" ) ) 161 { 162 bud->flags |= JBFLAG_DOES_XEP85; 163 imcb_buddy_typing( ic, from, OPT_THINKING ); 152 153 if (s) { 154 *s = '/'; /* And convert it back to a full JID. */ 164 155 } 165 166 if( s )167 *s = '/'; /* And convert it back to a full JID. */168 156 } 169 157 170 158 return XT_HANDLED; 171 159 } -
protocols/jabber/presence.c
raf359b4 r5ebff60 24 24 #include "jabber.h" 25 25 26 xt_status jabber_pkt_presence( struct xt_node *node, gpointer data)26 xt_status jabber_pkt_presence(struct xt_node *node, gpointer data) 27 27 { 28 28 struct im_connection *ic = data; 29 char *from = xt_find_attr( node, "from");30 char *type = xt_find_attr( node, "type" );/* NULL should mean the person is online. */29 char *from = xt_find_attr(node, "from"); 30 char *type = xt_find_attr(node, "type"); /* NULL should mean the person is online. */ 31 31 struct xt_node *c, *cap; 32 32 struct jabber_buddy *bud, *send_presence = NULL; 33 33 int is_chat = 0; 34 34 char *s; 35 36 if ( !from )35 36 if (!from) { 37 37 return XT_HANDLED; 38 39 if( ( s = strchr( from, '/' ) ) ) 40 {38 } 39 40 if ((s = strchr(from, '/'))) { 41 41 *s = 0; 42 if ( jabber_chat_by_jid( ic, from ) )42 if (jabber_chat_by_jid(ic, from)) { 43 43 is_chat = 1; 44 } 44 45 *s = '/'; 45 46 } 46 47 if( type == NULL ) 48 { 49 if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) 50 { 47 48 if (type == NULL) { 49 if (!(bud = jabber_buddy_by_jid(ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT))) { 51 50 /* 52 51 imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from ); … … 54 53 return XT_HANDLED; 55 54 } 56 57 g_free( bud->away_message);58 if ( ( c = xt_find_node( node->children, "status" ) ) && c->text_len > 0 )59 bud->away_message = g_strdup( c->text);60 else55 56 g_free(bud->away_message); 57 if ((c = xt_find_node(node->children, "status")) && c->text_len > 0) { 58 bud->away_message = g_strdup(c->text); 59 } else { 61 60 bud->away_message = NULL; 62 63 if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 ) 64 { 65 bud->away_state = (void*) jabber_away_state_by_code( c->text ); 66 } 67 else 68 { 61 } 62 63 if ((c = xt_find_node(node->children, "show")) && c->text_len > 0) { 64 bud->away_state = (void *) jabber_away_state_by_code(c->text); 65 } else { 69 66 bud->away_state = NULL; 70 67 } 71 72 if ( ( c = xt_find_node( node->children, "priority" ) ) && c->text_len > 0 )73 bud->priority = atoi( c->text);74 else68 69 if ((c = xt_find_node(node->children, "priority")) && c->text_len > 0) { 70 bud->priority = atoi(c->text); 71 } else { 75 72 bud->priority = 0; 76 77 if( bud && ( cap = xt_find_node( node->children, "c" ) ) && 78 ( s = xt_find_attr( cap, "xmlns" ) ) && strcmp( s, XMLNS_CAPS ) == 0 )79 {73 } 74 75 if (bud && (cap = xt_find_node(node->children, "c")) && 76 (s = xt_find_attr(cap, "xmlns")) && strcmp(s, XMLNS_CAPS) == 0) { 80 77 /* This <presence> stanza includes an XEP-0115 81 78 capabilities part. Not too interesting, but we can 82 79 see if it has an ext= attribute. */ 83 s = xt_find_attr( cap, "ext");84 if ( s && ( strstr( s, "cstates" ) || strstr( s, "chatstate" ) ) )80 s = xt_find_attr(cap, "ext"); 81 if (s && (strstr(s, "cstates") || strstr(s, "chatstate"))) { 85 82 bud->flags |= JBFLAG_DOES_XEP85; 86 83 } 84 87 85 /* This field can contain more information like xhtml 88 86 support, but we don't support that ourselves. 89 87 Officially the ext= tag was deprecated, but enough 90 88 clients do send it. 91 89 92 90 (I'm aware that this is not the right way to use 93 91 this field.) See for an explanation of ext=: 94 92 http://www.xmpp.org/extensions/attic/xep-0115-1.3.html*/ 95 93 } 96 97 if( is_chat ) 98 jabber_chat_pkt_presence( ic, bud, node ); 99 else 100 send_presence = jabber_buddy_by_jid( ic, bud->bare_jid, 0 ); 101 } 102 else if( strcmp( type, "unavailable" ) == 0 ) 103 { 104 if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL ) 105 { 94 95 if (is_chat) { 96 jabber_chat_pkt_presence(ic, bud, node); 97 } else { 98 send_presence = jabber_buddy_by_jid(ic, bud->bare_jid, 0); 99 } 100 } else if (strcmp(type, "unavailable") == 0) { 101 if ((bud = jabber_buddy_by_jid(ic, from, 0)) == NULL) { 106 102 /* 107 103 imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from ); … … 109 105 return XT_HANDLED; 110 106 } 111 107 112 108 /* Handle this before we delete the JID. */ 113 if( is_chat ) 114 { 115 jabber_chat_pkt_presence( ic, bud, node ); 116 } 117 118 if( strchr( from, '/' ) == NULL ) 109 if (is_chat) { 110 jabber_chat_pkt_presence(ic, bud, node); 111 } 112 113 if (strchr(from, '/') == NULL) { 119 114 /* Sometimes servers send a type="unavailable" from a 120 115 bare JID, which should mean that suddenly all 121 116 resources for this JID disappeared. */ 122 jabber_buddy_remove_bare( ic, from);123 else124 jabber_buddy_remove( ic, from);125 126 if( is_chat ) 127 {117 jabber_buddy_remove_bare(ic, from); 118 } else { 119 jabber_buddy_remove(ic, from); 120 } 121 122 if (is_chat) { 128 123 /* Nothing else to do for now? */ 129 } 130 else if( ( s = strchr( from, '/' ) ) ) 131 { 124 } else if ((s = strchr(from, '/'))) { 132 125 *s = 0; 133 126 134 127 /* If another resource is still available, send its presence 135 128 information. */ 136 if( ( send_presence = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL ) 137 { 129 if ((send_presence = jabber_buddy_by_jid(ic, from, 0)) == NULL) { 138 130 /* Otherwise, count him/her as offline now. */ 139 imcb_buddy_status( ic, from, 0, NULL, NULL);131 imcb_buddy_status(ic, from, 0, NULL, NULL); 140 132 } 141 133 142 134 *s = '/'; 143 } 144 else 145 { 146 imcb_buddy_status( ic, from, 0, NULL, NULL ); 147 } 148 } 149 else if( strcmp( type, "subscribe" ) == 0 ) 150 { 151 jabber_buddy_ask( ic, from ); 152 } 153 else if( strcmp( type, "subscribed" ) == 0 ) 154 { 135 } else { 136 imcb_buddy_status(ic, from, 0, NULL, NULL); 137 } 138 } else if (strcmp(type, "subscribe") == 0) { 139 jabber_buddy_ask(ic, from); 140 } else if (strcmp(type, "subscribed") == 0) { 155 141 /* Not sure about this one, actually... */ 156 imcb_log( ic, "%s just accepted your authorization request", from ); 157 } 158 else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 ) 159 { 142 imcb_log(ic, "%s just accepted your authorization request", from); 143 } else if (strcmp(type, "unsubscribe") == 0 || strcmp(type, "unsubscribed") == 0) { 160 144 /* Do nothing here. Plenty of control freaks or over-curious 161 145 souls get excited when they can see who still has them in … … 163 147 got the impression that those are the people who get 164 148 removed from many buddy lists for "some" reason... 165 149 166 150 If you're one of those people, this is your chance to write 167 151 your first line of code in C... */ 168 } 169 else if( strcmp( type, "error" ) == 0 ) 170 { 171 return jabber_cache_handle_packet( ic, node ); 172 152 } else if (strcmp(type, "error") == 0) { 153 return jabber_cache_handle_packet(ic, node); 154 173 155 /* 174 156 struct jabber_error *err; 175 157 if( ( c = xt_find_node( node->children, "error" ) ) ) 176 158 { 177 178 179 180 181 159 err = jabber_error_parse( c, XMLNS_STANZA_ERROR ); 160 imcb_error( ic, "Stanza (%s) error: %s%s%s", node->name, 161 err->code, err->text ? ": " : "", 162 err->text ? err->text : "" ); 163 jabber_error_free( err ); 182 164 } */ 183 165 } 184 166 185 if( send_presence ) 186 { 167 if (send_presence) { 187 168 int is_away = 0; 188 169 189 if (send_presence->away_state &&190 strcmp( send_presence->away_state->code, "chat" ) != 0 )170 if (send_presence->away_state && 171 strcmp(send_presence->away_state->code, "chat") != 0) { 191 172 is_away = OPT_AWAY; 192 193 imcb_buddy_status( ic, send_presence->bare_jid, OPT_LOGGED_IN | is_away, 194 is_away ? send_presence->away_state->full_name : NULL, 195 send_presence->away_message ); 196 } 197 173 } 174 175 imcb_buddy_status(ic, send_presence->bare_jid, OPT_LOGGED_IN | is_away, 176 is_away ? send_presence->away_state->full_name : NULL, 177 send_presence->away_message); 178 } 179 198 180 return XT_HANDLED; 199 181 } … … 201 183 /* Whenever presence information is updated, call this function to inform the 202 184 server. */ 203 int presence_send_update( struct im_connection *ic)185 int presence_send_update(struct im_connection *ic) 204 186 { 205 187 struct jabber_data *jd = ic->proto_data; … … 207 189 GSList *l; 208 190 int st; 209 210 node = jabber_make_packet( "presence", NULL, NULL, NULL ); 211 xt_add_child( node, xt_new_node( "priority", set_getstr( &ic->acc->set, "priority" ), NULL ) ); 212 if( jd->away_state ) 213 xt_add_child( node, xt_new_node( "show", jd->away_state->code, NULL ) ); 214 if( jd->away_message ) 215 xt_add_child( node, xt_new_node( "status", jd->away_message, NULL ) ); 216 191 192 node = jabber_make_packet("presence", NULL, NULL, NULL); 193 xt_add_child(node, xt_new_node("priority", set_getstr(&ic->acc->set, "priority"), NULL)); 194 if (jd->away_state) { 195 xt_add_child(node, xt_new_node("show", jd->away_state->code, NULL)); 196 } 197 if (jd->away_message) { 198 xt_add_child(node, xt_new_node("status", jd->away_message, NULL)); 199 } 200 217 201 /* This makes the packet slightly bigger, but clients interested in 218 202 capabilities can now cache the discovery info. This reduces the 219 203 usual post-login iq-flood. See XEP-0115. At least libpurple and 220 204 Trillian seem to do this right. */ 221 cap = xt_new_node( "c", NULL, NULL);222 xt_add_attr( cap, "xmlns", XMLNS_CAPS);223 xt_add_attr( cap, "node", "http://bitlbee.org/xmpp/caps");224 xt_add_attr( cap, "ver", BITLBEE_VERSION );/* The XEP wants this hashed, but nobody's doing that. */225 xt_add_child( node, cap);226 227 st = jabber_write_packet( ic, node);228 205 cap = xt_new_node("c", NULL, NULL); 206 xt_add_attr(cap, "xmlns", XMLNS_CAPS); 207 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps"); 208 xt_add_attr(cap, "ver", BITLBEE_VERSION); /* The XEP wants this hashed, but nobody's doing that. */ 209 xt_add_child(node, cap); 210 211 st = jabber_write_packet(ic, node); 212 229 213 /* Have to send this update to all groupchats too, the server won't 230 214 do this automatically. */ 231 for( l = ic->groupchats; l && st; l = l->next ) 232 { 215 for (l = ic->groupchats; l && st; l = l->next) { 233 216 struct groupchat *c = l->data; 234 217 struct jabber_chat *jc = c->data; 235 236 xt_add_attr( node, "to", jc->my_full_jid);237 st = jabber_write_packet( ic, node);238 } 239 240 xt_free_node( node);218 219 xt_add_attr(node, "to", jc->my_full_jid); 220 st = jabber_write_packet(ic, node); 221 } 222 223 xt_free_node(node); 241 224 return st; 242 225 } 243 226 244 227 /* Send a subscribe/unsubscribe request to a buddy. */ 245 int presence_send_request( struct im_connection *ic, char *handle, char *request)228 int presence_send_request(struct im_connection *ic, char *handle, char *request) 246 229 { 247 230 struct xt_node *node; 248 231 int st; 249 250 node = jabber_make_packet( "presence", NULL, NULL, NULL);251 xt_add_attr( node, "to", handle);252 xt_add_attr( node, "type", request);253 254 st = jabber_write_packet( ic, node);255 256 xt_free_node( node);232 233 node = jabber_make_packet("presence", NULL, NULL, NULL); 234 xt_add_attr(node, "to", handle); 235 xt_add_attr(node, "type", request); 236 237 st = jabber_write_packet(ic, node); 238 239 xt_free_node(node); 257 240 return st; 258 241 } -
protocols/jabber/s5bytestream.c
raf359b4 r5ebff60 34 34 GSList *streamhosts; 35 35 36 enum 37 { 38 BS_PHASE_CONNECT, 39 BS_PHASE_CONNECTED, 40 BS_PHASE_REQUEST, 36 enum { 37 BS_PHASE_CONNECT, 38 BS_PHASE_CONNECTED, 39 BS_PHASE_REQUEST, 41 40 BS_PHASE_REPLY 42 41 } phase; … … 46 45 47 46 gint connect_timeout; 48 47 49 48 char peek_buf[64]; 50 49 int peek_buf_len; 51 50 }; 52 51 53 struct socks5_message 54 { 52 struct socks5_message { 55 53 unsigned char ver; 56 union 57 { 54 union { 58 55 unsigned char cmd; 59 56 unsigned char rep; … … 64 61 unsigned char address[40]; 65 62 in_port_t port; 66 } __attribute__ ((packed)); 63 } __attribute__ ((packed)); 67 64 68 65 char *socks5_reply_code[] = { … … 76 73 "Command not supported", 77 74 "Address type not supported", 78 "unassigned"}; 75 "unassigned" 76 }; 79 77 80 78 /* connect() timeout in seconds. */ … … 85 83 /* very useful */ 86 84 #define ASSERTSOCKOP(op, msg) \ 87 if ( (op) == -1 )\88 return jabber_bs_abort( bt , msg ": %s", strerror( errno ) );89 90 gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ...);91 void jabber_bs_canceled( file_transfer_t *ft , char *reason);92 void jabber_bs_free_transfer( file_transfer_t *ft);93 gboolean jabber_bs_connect_timeout( gpointer data, gint fd, b_input_condition cond);94 gboolean jabber_bs_poll( struct bs_transfer *bt, int fd, short *revents);95 gboolean jabber_bs_peek( struct bs_transfer *bt, void *buffer, int buflen);96 97 void jabber_bs_recv_answer_request( struct bs_transfer *bt);98 gboolean jabber_bs_recv_read( gpointer data, gint fd, b_input_condition cond);99 gboolean jabber_bs_recv_write_request( file_transfer_t *ft);100 gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition cond);101 gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error);102 int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);103 104 gboolean jabber_bs_send_handshake_abort( struct bs_transfer *bt, char *error);105 gboolean jabber_bs_send_request( struct jabber_transfer *tf, GSList *streamhosts);106 gboolean jabber_bs_send_handshake( gpointer data, gint fd, b_input_condition cond);107 static xt_status jabber_bs_send_handle_activate( struct im_connection *ic, struct xt_node *node, struct xt_node *orig);108 void jabber_bs_send_activate( struct bs_transfer *bt);85 if ((op) == -1) { \ 86 return jabber_bs_abort(bt, msg ": %s", strerror(errno)); } 87 88 gboolean jabber_bs_abort(struct bs_transfer *bt, char *format, ...); 89 void jabber_bs_canceled(file_transfer_t *ft, char *reason); 90 void jabber_bs_free_transfer(file_transfer_t *ft); 91 gboolean jabber_bs_connect_timeout(gpointer data, gint fd, b_input_condition cond); 92 gboolean jabber_bs_poll(struct bs_transfer *bt, int fd, short *revents); 93 gboolean jabber_bs_peek(struct bs_transfer *bt, void *buffer, int buflen); 94 95 void jabber_bs_recv_answer_request(struct bs_transfer *bt); 96 gboolean jabber_bs_recv_read(gpointer data, gint fd, b_input_condition cond); 97 gboolean jabber_bs_recv_write_request(file_transfer_t *ft); 98 gboolean jabber_bs_recv_handshake(gpointer data, gint fd, b_input_condition cond); 99 gboolean jabber_bs_recv_handshake_abort(struct bs_transfer *bt, char *error); 100 int jabber_bs_recv_request(struct im_connection *ic, struct xt_node *node, struct xt_node *qnode); 101 102 gboolean jabber_bs_send_handshake_abort(struct bs_transfer *bt, char *error); 103 gboolean jabber_bs_send_request(struct jabber_transfer *tf, GSList *streamhosts); 104 gboolean jabber_bs_send_handshake(gpointer data, gint fd, b_input_condition cond); 105 static xt_status jabber_bs_send_handle_activate(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 106 void jabber_bs_send_activate(struct bs_transfer *bt); 109 107 110 108 /* 111 109 * Frees a bs_transfer struct and calls the SI free function 112 110 */ 113 void jabber_bs_free_transfer( file_transfer_t *ft) { 111 void jabber_bs_free_transfer(file_transfer_t *ft) 112 { 114 113 struct jabber_transfer *tf = ft->data; 115 114 struct bs_transfer *bt = tf->streamhandle; 116 115 jabber_streamhost_t *sh; 117 116 118 if ( bt->connect_timeout ) 119 { 120 b_event_remove( bt->connect_timeout ); 117 if (bt->connect_timeout) { 118 b_event_remove(bt->connect_timeout); 121 119 bt->connect_timeout = 0; 122 120 } 123 121 124 if ( tf->watch_in ) 125 { 126 b_event_remove( tf->watch_in ); 122 if (tf->watch_in) { 123 b_event_remove(tf->watch_in); 127 124 tf->watch_in = 0; 128 125 } 129 130 if( tf->watch_out ) 131 { 132 b_event_remove( tf->watch_out ); 126 127 if (tf->watch_out) { 128 b_event_remove(tf->watch_out); 133 129 tf->watch_out = 0; 134 130 } 135 136 g_free( bt->pseudoadr ); 137 138 while( bt->streamhosts ) 139 { 131 132 g_free(bt->pseudoadr); 133 134 while (bt->streamhosts) { 140 135 sh = bt->streamhosts->data; 141 bt->streamhosts = g_slist_remove( bt->streamhosts, sh);142 g_free( sh->jid);143 g_free( sh->host);144 g_free( sh);145 } 146 147 g_free( bt);148 149 jabber_si_free_transfer( ft);136 bt->streamhosts = g_slist_remove(bt->streamhosts, sh); 137 g_free(sh->jid); 138 g_free(sh->host); 139 g_free(sh); 140 } 141 142 g_free(bt); 143 144 jabber_si_free_transfer(ft); 150 145 } 151 146 … … 154 149 * writes it to buffer if that's the case. 155 150 */ 156 gboolean jabber_bs_peek( struct bs_transfer *bt, void *buffer, int buflen)151 gboolean jabber_bs_peek(struct bs_transfer *bt, void *buffer, int buflen) 157 152 { 158 153 int ret; 159 154 int fd = bt->tf->fd; 160 155 161 if( buflen > sizeof( bt->peek_buf ) ) 162 return jabber_bs_abort( bt, "BUG: %d > sizeof(peek_buf)", buflen ); 163 164 ASSERTSOCKOP( ret = recv( fd, bt->peek_buf + bt->peek_buf_len, 165 buflen - bt->peek_buf_len, 0 ), "recv() on SOCKS5 connection" ); 166 167 if( ret == 0 ) 168 return jabber_bs_abort( bt, "Remote end closed connection" ); 169 156 if (buflen > sizeof(bt->peek_buf)) { 157 return jabber_bs_abort(bt, "BUG: %d > sizeof(peek_buf)", buflen); 158 } 159 160 ASSERTSOCKOP(ret = recv(fd, bt->peek_buf + bt->peek_buf_len, 161 buflen - bt->peek_buf_len, 0), "recv() on SOCKS5 connection"); 162 163 if (ret == 0) { 164 return jabber_bs_abort(bt, "Remote end closed connection"); 165 } 166 170 167 bt->peek_buf_len += ret; 171 memcpy( buffer, bt->peek_buf, bt->peek_buf_len ); 172 173 if( bt->peek_buf_len == buflen ) 174 { 168 memcpy(buffer, bt->peek_buf, bt->peek_buf_len); 169 170 if (bt->peek_buf_len == buflen) { 175 171 /* If we have everything the caller wanted, reset the peek buffer. */ 176 172 bt->peek_buf_len = 0; 177 173 return buflen; 178 } 179 else 174 } else { 180 175 return bt->peek_buf_len; 181 } 182 183 184 /* 176 } 177 } 178 179 180 /* 185 181 * This function is scheduled in bs_handshake via b_timeout_add after a (non-blocking) connect(). 186 182 */ 187 gboolean jabber_bs_connect_timeout( gpointer data, gint fd, b_input_condition cond)183 gboolean jabber_bs_connect_timeout(gpointer data, gint fd, b_input_condition cond) 188 184 { 189 185 struct bs_transfer *bt = data; … … 191 187 bt->connect_timeout = 0; 192 188 193 jabber_bs_abort( bt, "no connection after %d seconds", bt->tf->ft->sending ? JABBER_BS_LISTEN_TIMEOUT : JABBER_BS_CONTIMEOUT ); 189 jabber_bs_abort(bt, "no connection after %d seconds", 190 bt->tf->ft->sending ? JABBER_BS_LISTEN_TIMEOUT : JABBER_BS_CONTIMEOUT); 194 191 195 192 return FALSE; 196 193 } 197 194 198 /* 195 /* 199 196 * Polls the socket, checks for errors and removes a connect timer 200 197 * if there is one. 201 198 */ 202 gboolean jabber_bs_poll( struct bs_transfer *bt, int fd, short *revents ) 203 { 204 struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR }; 205 206 if ( bt->connect_timeout ) 207 { 208 b_event_remove( bt->connect_timeout ); 199 gboolean jabber_bs_poll(struct bs_transfer *bt, int fd, short *revents) 200 { 201 struct pollfd pfd = { .fd = fd, .events = POLLHUP | POLLERR }; 202 203 if (bt->connect_timeout) { 204 b_event_remove(bt->connect_timeout); 209 205 bt->connect_timeout = 0; 210 206 } 211 207 212 ASSERTSOCKOP( poll( &pfd, 1, 0 ), "poll()" ) 213 214 if( pfd.revents & POLLERR ) 215 { 208 ASSERTSOCKOP(poll(&pfd, 1, 0), "poll()") 209 210 if (pfd.revents & POLLERR) { 216 211 int sockerror; 217 socklen_t errlen = sizeof( sockerror ); 218 219 if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) ) 220 return jabber_bs_abort( bt, "getsockopt() failed, unknown socket error during SOCKS5 handshake (weird!)" ); 221 222 if ( bt->phase == BS_PHASE_CONNECTED ) 223 return jabber_bs_abort( bt, "connect failed: %s", strerror( sockerror ) ); 224 225 return jabber_bs_abort( bt, "Socket error during SOCKS5 handshake(weird!): %s", strerror( sockerror ) ); 226 } 227 228 if( pfd.revents & POLLHUP ) 229 return jabber_bs_abort( bt, "Remote end closed connection" ); 230 212 socklen_t errlen = sizeof(sockerror); 213 214 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen)) { 215 return jabber_bs_abort(bt, 216 "getsockopt() failed, unknown socket error during SOCKS5 handshake (weird!)"); 217 } 218 219 if (bt->phase == BS_PHASE_CONNECTED) { 220 return jabber_bs_abort(bt, "connect failed: %s", strerror(sockerror)); 221 } 222 223 return jabber_bs_abort(bt, "Socket error during SOCKS5 handshake(weird!): %s", strerror(sockerror)); 224 } 225 226 if (pfd.revents & POLLHUP) { 227 return jabber_bs_abort(bt, "Remote end closed connection"); 228 } 229 231 230 *revents = pfd.revents; 232 231 233 232 return TRUE; 234 233 } … … 237 236 * Used for receive and send path. 238 237 */ 239 gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ...)238 gboolean jabber_bs_abort(struct bs_transfer *bt, char *format, ...) 240 239 { 241 240 va_list params; 242 va_start( params, format ); 241 242 va_start(params, format); 243 243 char error[128]; 244 244 245 if( vsnprintf( error, 128, format, params ) < 0 ) 246 sprintf( error, "internal error parsing error string (BUG)" ); 247 va_end( params ); 248 if( bt->tf->ft->sending ) 249 return jabber_bs_send_handshake_abort( bt, error ); 250 else 251 return jabber_bs_recv_handshake_abort( bt, error ); 245 if (vsnprintf(error, 128, format, params) < 0) { 246 sprintf(error, "internal error parsing error string (BUG)"); 247 } 248 va_end(params); 249 if (bt->tf->ft->sending) { 250 return jabber_bs_send_handshake_abort(bt, error); 251 } else { 252 return jabber_bs_recv_handshake_abort(bt, error); 253 } 252 254 } 253 255 254 256 /* Bad luck */ 255 void jabber_bs_canceled( file_transfer_t *ft , char *reason)257 void jabber_bs_canceled(file_transfer_t *ft, char *reason) 256 258 { 257 259 struct jabber_transfer *tf = ft->data; 258 260 259 imcb_log( tf->ic, "File transfer aborted: %s", reason);261 imcb_log(tf->ic, "File transfer aborted: %s", reason); 260 262 } 261 263 … … 263 265 * Parses an incoming bytestream request and calls jabber_bs_handshake on success. 264 266 */ 265 int jabber_bs_recv_request( 267 int jabber_bs_recv_request(struct im_connection *ic, struct xt_node *node, struct xt_node *qnode) 266 268 { 267 269 char *sid, *ini_jid, *tgt_jid, *mode, *iq_id; … … 270 272 GSList *tflist; 271 273 struct bs_transfer *bt; 272 GSList *shlist =NULL;274 GSList *shlist = NULL; 273 275 struct xt_node *shnode; 274 276 … … 277 279 unsigned char hash[20]; 278 280 int i; 279 280 if( !(iq_id = xt_find_attr( node, "id" ) ) || 281 !(ini_jid = xt_find_attr( node, "from" ) ) || 282 !(tgt_jid = xt_find_attr( node, "to" ) ) || 283 !(sid = xt_find_attr( qnode, "sid" ) ) ) 284 { 285 imcb_log( ic, "WARNING: Received incomplete SI bytestream request"); 281 282 if (!(iq_id = xt_find_attr(node, "id")) || 283 !(ini_jid = xt_find_attr(node, "from")) || 284 !(tgt_jid = xt_find_attr(node, "to")) || 285 !(sid = xt_find_attr(qnode, "sid"))) { 286 imcb_log(ic, "WARNING: Received incomplete SI bytestream request"); 286 287 return XT_HANDLED; 287 288 } 288 289 289 if ( ( mode = xt_find_attr( qnode, "mode" )) &&290 ( strcmp( mode, "tcp" ) != 0 ) )291 {292 imcb_log( ic, "WARNING: Received SI Request for unsupported bytestream mode %s", xt_find_attr( qnode, "mode" ));290 if ((mode = xt_find_attr(qnode, "mode")) && 291 (strcmp(mode, "tcp") != 0)) { 292 imcb_log(ic, "WARNING: Received SI Request for unsupported bytestream mode %s", 293 xt_find_attr(qnode, "mode")); 293 294 return XT_HANDLED; 294 295 } 295 296 296 297 shnode = qnode->children; 297 while( ( shnode = xt_find_node( shnode, "streamhost" ) ) ) 298 { 298 while ((shnode = xt_find_node(shnode, "streamhost"))) { 299 299 char *jid, *host, *port_s; 300 300 int port; 301 if( ( jid = xt_find_attr( shnode, "jid" ) ) && 302 ( host = xt_find_attr( shnode, "host" ) ) && 303 ( port_s = xt_find_attr( shnode, "port" ) ) && 304 ( sscanf( port_s, "%d", &port ) == 1 ) ) 305 { 306 jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 ); 301 if ((jid = xt_find_attr(shnode, "jid")) && 302 (host = xt_find_attr(shnode, "host")) && 303 (port_s = xt_find_attr(shnode, "port")) && 304 (sscanf(port_s, "%d", &port) == 1)) { 305 jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1); 307 306 sh->jid = g_strdup(jid); 308 307 sh->host = g_strdup(host); 309 sprintf( sh->port, "%u", port);310 shlist = g_slist_append( shlist, sh);308 sprintf(sh->port, "%u", port); 309 shlist = g_slist_append(shlist, sh); 311 310 } 312 311 shnode = shnode->next; 313 312 } 314 315 if( !shlist ) 316 { 317 imcb_log( ic, "WARNING: Received incomplete SI bytestream request, no parseable streamhost entries"); 313 314 if (!shlist) { 315 imcb_log(ic, "WARNING: Received incomplete SI bytestream request, no parseable streamhost entries"); 318 316 return XT_HANDLED; 319 317 } … … 321 319 /* Let's see if we can find out what this bytestream should be for... */ 322 320 323 for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) ) 324 { 321 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 325 322 struct jabber_transfer *tft = tflist->data; 326 if( ( strcmp( tft->sid, sid ) == 0 ) && 327 ( strcmp( tft->ini_jid, ini_jid ) == 0 ) && 328 ( strcmp( tft->tgt_jid, tgt_jid ) == 0 ) ) 329 { 330 tf = tft; 323 if ((strcmp(tft->sid, sid) == 0) && 324 (strcmp(tft->ini_jid, ini_jid) == 0) && 325 (strcmp(tft->tgt_jid, tgt_jid) == 0)) { 326 tf = tft; 331 327 break; 332 328 } 333 329 } 334 330 335 if (!tf) 336 { 337 imcb_log( ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid ); 331 if (!tf) { 332 imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid); 338 333 return XT_HANDLED; 339 334 } 340 335 341 336 /* iq_id and canceled can be reused since SI is done */ 342 g_free( tf->iq_id);343 tf->iq_id = g_strdup( iq_id);337 g_free(tf->iq_id); 338 tf->iq_id = g_strdup(iq_id); 344 339 345 340 tf->ft->canceled = jabber_bs_canceled; 346 341 347 342 /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */ 348 sha1_init( &sha ); 349 sha1_append( &sha, (unsigned char*) sid, strlen( sid ) ); 350 sha1_append( &sha, (unsigned char*) ini_jid, strlen( ini_jid ) ); 351 sha1_append( &sha, (unsigned char*) tgt_jid, strlen( tgt_jid ) ); 352 sha1_finish( &sha, hash ); 353 354 for( i = 0; i < 20; i ++ ) 355 sprintf( hash_hex + i * 2, "%02x", hash[i] ); 356 357 bt = g_new0( struct bs_transfer, 1 ); 343 sha1_init(&sha); 344 sha1_append(&sha, (unsigned char *) sid, strlen(sid)); 345 sha1_append(&sha, (unsigned char *) ini_jid, strlen(ini_jid)); 346 sha1_append(&sha, (unsigned char *) tgt_jid, strlen(tgt_jid)); 347 sha1_finish(&sha, hash); 348 349 for (i = 0; i < 20; i++) { 350 sprintf(hash_hex + i * 2, "%02x", hash[i]); 351 } 352 353 bt = g_new0(struct bs_transfer, 1); 358 354 bt->tf = tf; 359 355 bt->streamhosts = shlist; 360 356 bt->sh = shlist->data; 361 357 bt->phase = BS_PHASE_CONNECT; 362 bt->pseudoadr = g_strdup( hash_hex);358 bt->pseudoadr = g_strdup(hash_hex); 363 359 tf->streamhandle = bt; 364 360 tf->ft->free = jabber_bs_free_transfer; 365 361 366 jabber_bs_recv_handshake( bt, -1, 0 );362 jabber_bs_recv_handshake(bt, -1, 0); 367 363 368 364 return XT_HANDLED; … … 376 372 * All in all, it turned out quite nice :) 377 373 */ 378 gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition cond)374 gboolean jabber_bs_recv_handshake(gpointer data, gint fd, b_input_condition cond) 379 375 { 380 376 … … 383 379 int gret; 384 380 385 if ( ( fd != -1 ) && !jabber_bs_poll( bt, fd, &revents ) )381 if ((fd != -1) && !jabber_bs_poll(bt, fd, &revents)) { 386 382 return FALSE; 387 388 switch( bt->phase ) 383 } 384 385 switch (bt->phase) { 386 case BS_PHASE_CONNECT: 389 387 { 390 case BS_PHASE_CONNECT: 388 struct addrinfo hints, *rp; 389 390 memset(&hints, 0, sizeof(struct addrinfo)); 391 hints.ai_socktype = SOCK_STREAM; 392 393 if ((gret = getaddrinfo(bt->sh->host, bt->sh->port, &hints, &rp)) != 0) { 394 return jabber_bs_abort(bt, "getaddrinfo() failed: %s", gai_strerror(gret)); 395 } 396 397 ASSERTSOCKOP(bt->tf->fd = fd = socket(rp->ai_family, rp->ai_socktype, 0), "Opening socket"); 398 399 sock_make_nonblocking(fd); 400 401 imcb_log(bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, bt->sh->host, 402 bt->sh->port); 403 404 if ((connect(fd, rp->ai_addr, rp->ai_addrlen) == -1) && 405 (errno != EINPROGRESS)) { 406 return jabber_bs_abort(bt, "connect() failed: %s", strerror(errno)); 407 } 408 409 freeaddrinfo(rp); 410 411 bt->phase = BS_PHASE_CONNECTED; 412 413 bt->tf->watch_out = b_input_add(fd, B_EV_IO_WRITE, jabber_bs_recv_handshake, bt); 414 415 /* since it takes forever(3mins?) till connect() fails on itself we schedule a timeout */ 416 bt->connect_timeout = b_timeout_add(JABBER_BS_CONTIMEOUT * 1000, jabber_bs_connect_timeout, bt); 417 418 bt->tf->watch_in = 0; 419 return FALSE; 420 } 421 case BS_PHASE_CONNECTED: 422 { 423 struct { 424 unsigned char ver; 425 unsigned char nmethods; 426 unsigned char method; 427 } socks5_hello = { 428 .ver = 5, 429 .nmethods = 1, 430 .method = 0x00 /* no auth */ 431 /* one could also implement username/password. If you know 432 * a jabber client or proxy that actually does it, tell me. 433 */ 434 }; 435 436 ASSERTSOCKOP(send(fd, &socks5_hello, sizeof(socks5_hello), 0), "Sending auth request"); 437 438 bt->phase = BS_PHASE_REQUEST; 439 440 bt->tf->watch_in = b_input_add(fd, B_EV_IO_READ, jabber_bs_recv_handshake, bt); 441 442 bt->tf->watch_out = 0; 443 return FALSE; 444 } 445 case BS_PHASE_REQUEST: 446 { 447 struct socks5_message socks5_connect = 391 448 { 392 struct addrinfo hints, *rp; 393 394 memset( &hints, 0, sizeof( struct addrinfo ) ); 395 hints.ai_socktype = SOCK_STREAM; 396 397 if ( ( gret = getaddrinfo( bt->sh->host, bt->sh->port, &hints, &rp ) ) != 0 ) 398 return jabber_bs_abort( bt, "getaddrinfo() failed: %s", gai_strerror( gret ) ); 399 400 ASSERTSOCKOP( bt->tf->fd = fd = socket( rp->ai_family, rp->ai_socktype, 0 ), "Opening socket" ); 401 402 sock_make_nonblocking( fd ); 403 404 imcb_log( bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, bt->sh->host, bt->sh->port ); 405 406 if( ( connect( fd, rp->ai_addr, rp->ai_addrlen ) == -1 ) && 407 ( errno != EINPROGRESS ) ) 408 return jabber_bs_abort( bt , "connect() failed: %s", strerror( errno ) ); 409 410 freeaddrinfo( rp ); 411 412 bt->phase = BS_PHASE_CONNECTED; 413 414 bt->tf->watch_out = b_input_add( fd, B_EV_IO_WRITE, jabber_bs_recv_handshake, bt ); 415 416 /* since it takes forever(3mins?) till connect() fails on itself we schedule a timeout */ 417 bt->connect_timeout = b_timeout_add( JABBER_BS_CONTIMEOUT * 1000, jabber_bs_connect_timeout, bt ); 418 419 bt->tf->watch_in = 0; 449 .ver = 5, 450 .cmdrep.cmd = 0x01, 451 .rsv = 0, 452 .atyp = 0x03, 453 .addrlen = strlen(bt->pseudoadr), 454 .port = 0 455 }; 456 int ret; 457 char buf[2]; 458 459 /* If someone's trying to be funny and sends only one byte at a time we'll fail :) */ 460 ASSERTSOCKOP(ret = recv(fd, buf, 2, 0), "Receiving auth reply"); 461 462 if (!(ret == 2) || 463 !(buf[0] == 5) || 464 !(buf[1] == 0)) { 465 return jabber_bs_abort(bt, "Auth not accepted by streamhost (reply: len=%d, ver=%d, status=%d)", 466 ret, buf[0], buf[1]); 467 } 468 469 /* copy hash into connect message */ 470 memcpy(socks5_connect.address, bt->pseudoadr, socks5_connect.addrlen); 471 472 ASSERTSOCKOP(send(fd, &socks5_connect, sizeof(struct socks5_message), 0), "Sending SOCKS5 Connect"); 473 474 bt->phase = BS_PHASE_REPLY; 475 476 return TRUE; 477 } 478 case BS_PHASE_REPLY: 479 { 480 struct socks5_message socks5_reply; 481 int ret; 482 483 if (!(ret = jabber_bs_peek(bt, &socks5_reply, sizeof(struct socks5_message)))) { 420 484 return FALSE; 421 485 } 422 case BS_PHASE_CONNECTED: 423 { 424 struct { 425 unsigned char ver; 426 unsigned char nmethods; 427 unsigned char method; 428 } socks5_hello = { 429 .ver = 5, 430 .nmethods = 1, 431 .method = 0x00 /* no auth */ 432 /* one could also implement username/password. If you know 433 * a jabber client or proxy that actually does it, tell me. 434 */ 435 }; 436 437 ASSERTSOCKOP( send( fd, &socks5_hello, sizeof( socks5_hello ) , 0 ), "Sending auth request" ); 438 439 bt->phase = BS_PHASE_REQUEST; 440 441 bt->tf->watch_in = b_input_add( fd, B_EV_IO_READ, jabber_bs_recv_handshake, bt ); 442 443 bt->tf->watch_out = 0; 444 return FALSE; 445 } 446 case BS_PHASE_REQUEST: 447 { 448 struct socks5_message socks5_connect = 449 { 450 .ver = 5, 451 .cmdrep.cmd = 0x01, 452 .rsv = 0, 453 .atyp = 0x03, 454 .addrlen = strlen( bt->pseudoadr ), 455 .port = 0 456 }; 457 int ret; 458 char buf[2]; 459 460 /* If someone's trying to be funny and sends only one byte at a time we'll fail :) */ 461 ASSERTSOCKOP( ret = recv( fd, buf, 2, 0 ) , "Receiving auth reply" ); 462 463 if( !( ret == 2 ) || 464 !( buf[0] == 5 ) || 465 !( buf[1] == 0 ) ) 466 return jabber_bs_abort( bt, "Auth not accepted by streamhost (reply: len=%d, ver=%d, status=%d)", 467 ret, buf[0], buf[1] ); 468 469 /* copy hash into connect message */ 470 memcpy( socks5_connect.address, bt->pseudoadr, socks5_connect.addrlen ); 471 472 ASSERTSOCKOP( send( fd, &socks5_connect, sizeof( struct socks5_message ), 0 ) , "Sending SOCKS5 Connect" ); 473 474 bt->phase = BS_PHASE_REPLY; 475 486 487 if (ret < 5) { /* header up to address length */ 476 488 return TRUE; 477 } 478 case BS_PHASE_REPLY: 479 { 480 struct socks5_message socks5_reply; 481 int ret; 482 483 if ( !( ret = jabber_bs_peek( bt, &socks5_reply, sizeof( struct socks5_message ) ) ) ) 484 return FALSE; 485 486 if ( ret < 5 ) /* header up to address length */ 487 return TRUE; 488 else if( ret < sizeof( struct socks5_message ) ) 489 { 490 /* Either a buggy proxy or just one that doesnt regard 491 * the SHOULD in XEP-0065 saying the reply SHOULD 492 * contain the address. We'll take it, so make sure the 493 * next jabber_bs_peek starts with an empty buffer. */ 494 bt->peek_buf_len = 0; 489 } else if (ret < sizeof(struct socks5_message)) { 490 /* Either a buggy proxy or just one that doesnt regard 491 * the SHOULD in XEP-0065 saying the reply SHOULD 492 * contain the address. We'll take it, so make sure the 493 * next jabber_bs_peek starts with an empty buffer. */ 494 bt->peek_buf_len = 0; 495 } 496 497 if (!(socks5_reply.ver == 5) || 498 !(socks5_reply.cmdrep.rep == 0)) { 499 char errstr[128] = ""; 500 if ((socks5_reply.ver == 5) && (socks5_reply.cmdrep.rep < 501 (sizeof(socks5_reply_code) / sizeof(socks5_reply_code[0])))) { 502 sprintf(errstr, "with \"%s\" ", socks5_reply_code[ socks5_reply.cmdrep.rep ]); 495 503 } 496 497 if( !( socks5_reply.ver == 5 ) || 498 !( socks5_reply.cmdrep.rep == 0 ) ) { 499 char errstr[128] = ""; 500 if( ( socks5_reply.ver == 5 ) && ( socks5_reply.cmdrep.rep < 501 ( sizeof( socks5_reply_code ) / sizeof( socks5_reply_code[0] ) ) ) ) { 502 sprintf( errstr, "with \"%s\" ", socks5_reply_code[ socks5_reply.cmdrep.rep ] ); 503 } 504 return jabber_bs_abort( bt, "SOCKS5 CONNECT failed %s(reply: ver=%d, rep=%d, atyp=%d, addrlen=%d)", 505 errstr, 506 socks5_reply.ver, 507 socks5_reply.cmdrep.rep, 508 socks5_reply.atyp, 509 socks5_reply.addrlen); 510 } 511 512 /* usually a proxy sends back the 40 bytes address but I encountered at least one (of jabber.cz) 513 * that sends atyp=0 addrlen=0 and only 6 bytes (one less than one would expect). 514 * Therefore I removed the wait for more bytes. Since we don't care about what else the proxy 515 * is sending, it shouldnt matter */ 516 517 if( bt->tf->ft->sending ) 518 jabber_bs_send_activate( bt ); 519 else 520 jabber_bs_recv_answer_request( bt ); 521 522 return FALSE; 523 } 504 return jabber_bs_abort(bt, 505 "SOCKS5 CONNECT failed %s(reply: ver=%d, rep=%d, atyp=%d, addrlen=%d)", 506 errstr, 507 socks5_reply.ver, 508 socks5_reply.cmdrep.rep, 509 socks5_reply.atyp, 510 socks5_reply.addrlen); 511 } 512 513 /* usually a proxy sends back the 40 bytes address but I encountered at least one (of jabber.cz) 514 * that sends atyp=0 addrlen=0 and only 6 bytes (one less than one would expect). 515 * Therefore I removed the wait for more bytes. Since we don't care about what else the proxy 516 * is sending, it shouldnt matter */ 517 518 if (bt->tf->ft->sending) { 519 jabber_bs_send_activate(bt); 520 } else { 521 jabber_bs_recv_answer_request(bt); 522 } 523 524 return FALSE; 525 } 524 526 default: 525 527 /* BUG */ 526 imcb_log( bt->tf->ic, "BUG in file transfer code: undefined handshake phase");528 imcb_log(bt->tf->ic, "BUG in file transfer code: undefined handshake phase"); 527 529 528 530 bt->tf->watch_in = 0; … … 534 536 * If the handshake failed we can try the next streamhost, if there is one. 535 537 * An intelligent sender would probably specify himself as the first streamhost and 536 * a proxy as the second (Kopete and PSI are examples here). That way, a (potentially) 538 * a proxy as the second (Kopete and PSI are examples here). That way, a (potentially) 537 539 * slow proxy is only used if neccessary. This of course also means, that the timeout 538 540 * per streamhost should be kept short. If one or two firewalled adresses are specified, 539 541 * they have to timeout first before a proxy is tried. 540 542 */ 541 gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error)543 gboolean jabber_bs_recv_handshake_abort(struct bs_transfer *bt, char *error) 542 544 { 543 545 struct jabber_transfer *tf = bt->tf; … … 545 547 GSList *shlist; 546 548 547 imcb_log( tf->ic, "Transferring file %s: connection to streamhost %s:%s failed (%s)",548 tf->ft->file_name,549 550 551 error);549 imcb_log(tf->ic, "Transferring file %s: connection to streamhost %s:%s failed (%s)", 550 tf->ft->file_name, 551 bt->sh->host, 552 bt->sh->port, 553 error); 552 554 553 555 /* Alright, this streamhost failed, let's try the next... */ 554 556 bt->phase = BS_PHASE_CONNECT; 555 shlist = g_slist_find( bt->streamhosts, bt->sh ); 556 if( shlist && shlist->next ) 557 { 557 shlist = g_slist_find(bt->streamhosts, bt->sh); 558 if (shlist && shlist->next) { 558 559 bt->sh = shlist->next->data; 559 return jabber_bs_recv_handshake( bt, -1, 0);560 return jabber_bs_recv_handshake(bt, -1, 0); 560 561 } 561 562 … … 563 564 /* out of stream hosts */ 564 565 565 iqnode = jabber_make_packet( "iq", "result", tf->ini_jid, NULL ); 566 reply = jabber_make_error_packet( iqnode, "item-not-found", "cancel" , "404" ); 567 xt_free_node( iqnode ); 568 569 xt_add_attr( reply, "id", tf->iq_id ); 570 571 if( !jabber_write_packet( tf->ic, reply ) ) 572 imcb_log( tf->ic, "WARNING: Error transmitting bytestream response" ); 573 xt_free_node( reply ); 574 575 imcb_file_canceled( tf->ic, tf->ft, "couldn't connect to any streamhosts" ); 566 iqnode = jabber_make_packet("iq", "result", tf->ini_jid, NULL); 567 reply = jabber_make_error_packet(iqnode, "item-not-found", "cancel", "404"); 568 xt_free_node(iqnode); 569 570 xt_add_attr(reply, "id", tf->iq_id); 571 572 if (!jabber_write_packet(tf->ic, reply)) { 573 imcb_log(tf->ic, "WARNING: Error transmitting bytestream response"); 574 } 575 xt_free_node(reply); 576 577 imcb_file_canceled(tf->ic, tf->ft, "couldn't connect to any streamhosts"); 576 578 577 579 /* MUST always return FALSE! */ … … 579 581 } 580 582 581 /* 583 /* 582 584 * After the SOCKS5 handshake succeeds we need to inform the initiator which streamhost we chose. 583 585 * If he is the streamhost himself, he might already know that. However, if it's a proxy, 584 586 * the initiator will have to make a connection himself. 585 587 */ 586 void jabber_bs_recv_answer_request( struct bs_transfer *bt)588 void jabber_bs_recv_answer_request(struct bs_transfer *bt) 587 589 { 588 590 struct jabber_transfer *tf = bt->tf; 589 591 struct xt_node *reply; 590 592 591 imcb_log( tf->ic, "File %s: established SOCKS5 connection to %s:%s",592 tf->ft->file_name,593 594 bt->sh->port);593 imcb_log(tf->ic, "File %s: established SOCKS5 connection to %s:%s", 594 tf->ft->file_name, 595 bt->sh->host, 596 bt->sh->port); 595 597 596 598 tf->ft->data = tf; 597 tf->watch_in = b_input_add( tf->fd, B_EV_IO_READ, jabber_bs_recv_read, bt);599 tf->watch_in = b_input_add(tf->fd, B_EV_IO_READ, jabber_bs_recv_read, bt); 598 600 tf->ft->write_request = jabber_bs_recv_write_request; 599 601 600 reply = xt_new_node( "streamhost-used", NULL, NULL ); 601 xt_add_attr( reply, "jid", bt->sh->jid ); 602 603 reply = xt_new_node( "query", NULL, reply ); 604 xt_add_attr( reply, "xmlns", XMLNS_BYTESTREAMS ); 605 606 reply = jabber_make_packet( "iq", "result", tf->ini_jid, reply ); 607 608 xt_add_attr( reply, "id", tf->iq_id ); 609 610 if( !jabber_write_packet( tf->ic, reply ) ) 611 imcb_file_canceled( tf->ic, tf->ft, "Error transmitting bytestream response" ); 612 xt_free_node( reply ); 613 } 614 615 /* 602 reply = xt_new_node("streamhost-used", NULL, NULL); 603 xt_add_attr(reply, "jid", bt->sh->jid); 604 605 reply = xt_new_node("query", NULL, reply); 606 xt_add_attr(reply, "xmlns", XMLNS_BYTESTREAMS); 607 608 reply = jabber_make_packet("iq", "result", tf->ini_jid, reply); 609 610 xt_add_attr(reply, "id", tf->iq_id); 611 612 if (!jabber_write_packet(tf->ic, reply)) { 613 imcb_file_canceled(tf->ic, tf->ft, "Error transmitting bytestream response"); 614 } 615 xt_free_node(reply); 616 } 617 618 /* 616 619 * This function is called from write_request directly. If no data is available, it will install itself 617 620 * as a watcher for input on fd and once that happens, deliver the data and unschedule itself again. 618 621 */ 619 gboolean jabber_bs_recv_read( gpointer data, gint fd, b_input_condition cond)622 gboolean jabber_bs_recv_read(gpointer data, gint fd, b_input_condition cond) 620 623 { 621 624 int ret; … … 623 626 struct jabber_transfer *tf = bt->tf; 624 627 625 if( fd != -1 ) /* called via event thread */ 626 { 628 if (fd != -1) { /* called via event thread */ 627 629 tf->watch_in = 0; 628 ASSERTSOCKOP( ret = recv( fd, tf->ft->buffer, sizeof( tf->ft->buffer ), 0 ) , "Receiving" ); 629 } 630 else 631 { 630 ASSERTSOCKOP(ret = recv(fd, tf->ft->buffer, sizeof(tf->ft->buffer), 0), "Receiving"); 631 } else { 632 632 /* called directly. There might not be any data available. */ 633 if ( ( ( ret = recv( tf->fd, tf->ft->buffer, sizeof( tf->ft->buffer ), 0 ) ) == -1) &&634 ( errno != EAGAIN ) )635 return jabber_bs_abort( bt, "Receiving: %s", strerror( errno ));636 637 if( ( ret == -1 ) && ( errno == EAGAIN ) ) 638 {639 tf->watch_in = b_input_add( tf->fd, B_EV_IO_READ, jabber_bs_recv_read, bt);633 if (((ret = recv(tf->fd, tf->ft->buffer, sizeof(tf->ft->buffer), 0)) == -1) && 634 (errno != EAGAIN)) { 635 return jabber_bs_abort(bt, "Receiving: %s", strerror(errno)); 636 } 637 638 if ((ret == -1) && (errno == EAGAIN)) { 639 tf->watch_in = b_input_add(tf->fd, B_EV_IO_READ, jabber_bs_recv_read, bt); 640 640 return FALSE; 641 641 } … … 643 643 644 644 /* shouldn't happen since we know the file size */ 645 if( ret == 0 ) 646 return jabber_bs_abort( bt, "Remote end closed connection" ); 647 645 if (ret == 0) { 646 return jabber_bs_abort(bt, "Remote end closed connection"); 647 } 648 648 649 tf->bytesread += ret; 649 650 650 if( tf->bytesread >= tf->ft->file_size ) 651 imcb_file_finished( tf->ic, tf->ft ); 652 653 tf->ft->write( tf->ft, tf->ft->buffer, ret ); 651 if (tf->bytesread >= tf->ft->file_size) { 652 imcb_file_finished(tf->ic, tf->ft); 653 } 654 655 tf->ft->write(tf->ft, tf->ft->buffer, ret); 654 656 655 657 return FALSE; 656 658 } 657 659 658 /* 660 /* 659 661 * imc callback that is invoked when it is ready to receive some data. 660 662 */ 661 gboolean jabber_bs_recv_write_request( file_transfer_t *ft)663 gboolean jabber_bs_recv_write_request(file_transfer_t *ft) 662 664 { 663 665 struct jabber_transfer *tf = ft->data; 664 666 665 if ( tf->watch_in )666 {667 imcb_file_canceled( tf->ic, ft, "BUG in jabber file transfer: write_request called when already watching for input");667 if (tf->watch_in) { 668 imcb_file_canceled(tf->ic, ft, 669 "BUG in jabber file transfer: write_request called when already watching for input"); 668 670 return FALSE; 669 671 } 670 671 jabber_bs_recv_read( tf->streamhandle, -1 , 0);672 673 jabber_bs_recv_read(tf->streamhandle, -1, 0); 672 674 673 675 return TRUE; 674 676 } 675 677 676 /* 678 /* 677 679 * Issues a write_request to imc. 678 680 * */ 679 gboolean jabber_bs_send_can_write( gpointer data, gint fd, b_input_condition cond)681 gboolean jabber_bs_send_can_write(gpointer data, gint fd, b_input_condition cond) 680 682 { 681 683 struct bs_transfer *bt = data; … … 683 685 bt->tf->watch_out = 0; 684 686 685 bt->tf->ft->write_request( bt->tf->ft);687 bt->tf->ft->write_request(bt->tf->ft); 686 688 687 689 return FALSE; … … 692 694 * Add a write watch so we can write more during the next cycle (if possible). 693 695 */ 694 gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len)696 gboolean jabber_bs_send_write(file_transfer_t *ft, char *buffer, unsigned int len) 695 697 { 696 698 struct jabber_transfer *tf = ft->data; … … 698 700 int ret; 699 701 700 if( tf->watch_out ) 701 return jabber_bs_abort( bt, "BUG: write() called while watching " ); 702 702 if (tf->watch_out) { 703 return jabber_bs_abort(bt, "BUG: write() called while watching "); 704 } 705 703 706 /* TODO: catch broken pipe */ 704 ASSERTSOCKOP( ret = send( tf->fd, buffer, len, 0 ), "Sending");707 ASSERTSOCKOP(ret = send(tf->fd, buffer, len, 0), "Sending"); 705 708 706 709 tf->byteswritten += ret; 707 710 708 711 /* TODO: this should really not be fatal */ 709 if( ret < len ) 710 return jabber_bs_abort( bt, "send() sent %d instead of %d (send buffer too big!)", ret, len ); 711 712 if( tf->byteswritten >= ft->file_size ) 713 imcb_file_finished( tf->ic, ft ); 714 else 715 bt->tf->watch_out = b_input_add( tf->fd, B_EV_IO_WRITE, jabber_bs_send_can_write, bt ); 716 712 if (ret < len) { 713 return jabber_bs_abort(bt, "send() sent %d instead of %d (send buffer too big!)", ret, len); 714 } 715 716 if (tf->byteswritten >= ft->file_size) { 717 imcb_file_finished(tf->ic, ft); 718 } else { 719 bt->tf->watch_out = b_input_add(tf->fd, B_EV_IO_WRITE, jabber_bs_send_can_write, bt); 720 } 721 717 722 return TRUE; 718 723 } … … 721 726 * Handles the reply by the receiver containing the used streamhost. 722 727 */ 723 static xt_status jabber_bs_send_handle_reply(struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) { 728 static xt_status jabber_bs_send_handle_reply(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 729 { 724 730 struct jabber_transfer *tf = NULL; 725 731 struct jabber_data *jd = ic->proto_data; … … 729 735 char *sid, *jid; 730 736 731 if( !( c = xt_find_node( node->children, "query" ) ) || 732 !( c = xt_find_node( c->children, "streamhost-used" ) ) || 733 !( jid = xt_find_attr( c, "jid" ) ) ) 734 735 { 736 imcb_log( ic, "WARNING: Received incomplete bytestream reply" ); 737 if (!(c = xt_find_node(node->children, "query")) || 738 !(c = xt_find_node(c->children, "streamhost-used")) || 739 !(jid = xt_find_attr(c, "jid"))) { 740 imcb_log(ic, "WARNING: Received incomplete bytestream reply"); 737 741 return XT_HANDLED; 738 742 } 739 740 if( !( c = xt_find_node( orig->children, "query" ) ) || 741 !( sid = xt_find_attr( c, "sid" ) ) ) 742 { 743 imcb_log( ic, "WARNING: Error parsing request corresponding to the incoming bytestream reply" ); 743 744 if (!(c = xt_find_node(orig->children, "query")) || 745 !(sid = xt_find_attr(c, "sid"))) { 746 imcb_log(ic, "WARNING: Error parsing request corresponding to the incoming bytestream reply"); 744 747 return XT_HANDLED; 745 748 } … … 747 750 /* Let's see if we can find out what this bytestream should be for... */ 748 751 749 for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) ) 750 { 752 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 751 753 struct jabber_transfer *tft = tflist->data; 752 if( ( strcmp( tft->sid, sid ) == 0 ) ) 753 { 754 tf = tft; 754 if ((strcmp(tft->sid, sid) == 0)) { 755 tf = tft; 755 756 break; 756 757 } 757 758 } 758 759 759 if( !tf ) 760 { 761 imcb_log( ic, "WARNING: Received SOCKS5 bytestream reply to unknown request" ); 760 if (!tf) { 761 imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply to unknown request"); 762 762 return XT_HANDLED; 763 763 } … … 767 767 tf->accepted = TRUE; 768 768 769 if( strcmp( jid, tf->ini_jid ) == 0 ) 770 { 769 if (strcmp(jid, tf->ini_jid) == 0) { 771 770 /* we're streamhost and target */ 772 if( bt->phase == BS_PHASE_REPLY ) 773 { 771 if (bt->phase == BS_PHASE_REPLY) { 774 772 /* handshake went through, let's start transferring */ 775 tf->ft->write_request( tf->ft ); 776 } 777 } else 778 { 773 tf->ft->write_request(tf->ft); 774 } 775 } else { 779 776 /* using a proxy, abort listen */ 780 777 781 if( tf->watch_in ) 782 { 783 b_event_remove( tf->watch_in ); 778 if (tf->watch_in) { 779 b_event_remove(tf->watch_in); 784 780 tf->watch_in = 0; 785 781 } 786 787 if ( tf->fd != -1) {788 closesocket( tf->fd);782 783 if (tf->fd != -1) { 784 closesocket(tf->fd); 789 785 tf->fd = -1; 790 786 } 791 787 792 if ( bt->connect_timeout ) 793 { 794 b_event_remove( bt->connect_timeout ); 788 if (bt->connect_timeout) { 789 b_event_remove(bt->connect_timeout); 795 790 bt->connect_timeout = 0; 796 791 } 797 792 798 793 GSList *shlist; 799 for( shlist = jd->streamhosts ; shlist ; shlist = g_slist_next( shlist ) ) 800 { 794 for (shlist = jd->streamhosts; shlist; shlist = g_slist_next(shlist)) { 801 795 jabber_streamhost_t *sh = shlist->data; 802 if( strcmp( sh->jid, jid ) == 0 ) 803 { 796 if (strcmp(sh->jid, jid) == 0) { 804 797 bt->sh = sh; 805 jabber_bs_recv_handshake( bt, -1, 0);798 jabber_bs_recv_handshake(bt, -1, 0); 806 799 return XT_HANDLED; 807 800 } 808 801 } 809 802 810 imcb_log( ic, "WARNING: Received SOCKS5 bytestream reply with unknown streamhost %s", jid);803 imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply with unknown streamhost %s", jid); 811 804 } 812 805 … … 814 807 } 815 808 816 /* 809 /* 817 810 * Tell the proxy to activate the stream. Looks like this: 818 811 * 819 812 * <iq type=set> 820 * 821 * 822 * 813 * <query xmlns=bs sid=sid> 814 * <activate>tgt_jid</activate> 815 * </query> 823 816 * </iq> 824 817 */ 825 void jabber_bs_send_activate( struct bs_transfer *bt)818 void jabber_bs_send_activate(struct bs_transfer *bt) 826 819 { 827 820 struct xt_node *node; 828 821 829 node = xt_new_node( "activate", bt->tf->tgt_jid, NULL);830 node = xt_new_node( "query", NULL, node);831 xt_add_attr( node, "xmlns", XMLNS_BYTESTREAMS);832 xt_add_attr( node, "sid", bt->tf->sid);833 node = jabber_make_packet( "iq", "set", bt->sh->jid, node);834 835 jabber_cache_add( bt->tf->ic, node, jabber_bs_send_handle_activate);836 837 jabber_write_packet( bt->tf->ic, node);822 node = xt_new_node("activate", bt->tf->tgt_jid, NULL); 823 node = xt_new_node("query", NULL, node); 824 xt_add_attr(node, "xmlns", XMLNS_BYTESTREAMS); 825 xt_add_attr(node, "sid", bt->tf->sid); 826 node = jabber_make_packet("iq", "set", bt->sh->jid, node); 827 828 jabber_cache_add(bt->tf->ic, node, jabber_bs_send_handle_activate); 829 830 jabber_write_packet(bt->tf->ic, node); 838 831 } 839 832 … … 842 835 * We can finally start pushing some data out. 843 836 */ 844 static xt_status jabber_bs_send_handle_activate( struct im_connection *ic, struct xt_node *node, struct xt_node *orig)837 static xt_status jabber_bs_send_handle_activate(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 845 838 { 846 839 char *sid; … … 850 843 struct jabber_data *jd = ic->proto_data; 851 844 852 query = xt_find_node( orig->children, "query" ); 853 sid = xt_find_attr( query, "sid" ); 854 855 for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) ) 856 { 845 query = xt_find_node(orig->children, "query"); 846 sid = xt_find_attr(query, "sid"); 847 848 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 857 849 struct jabber_transfer *tft = tflist->data; 858 if( ( strcmp( tft->sid, sid ) == 0 ) ) 859 { 860 tf = tft; 850 if ((strcmp(tft->sid, sid) == 0)) { 851 tf = tft; 861 852 break; 862 853 } 863 854 } 864 855 865 if( !tf ) 866 { 867 imcb_log( ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream" ); 856 if (!tf) { 857 imcb_log(ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream"); 868 858 return XT_HANDLED; 869 859 } 870 860 871 imcb_log( tf->ic, "File %s: SOCKS5 handshake and activation successful! Transfer about to start...", tf->ft->file_name ); 861 imcb_log(tf->ic, "File %s: SOCKS5 handshake and activation successful! Transfer about to start...", 862 tf->ft->file_name); 872 863 873 864 /* handshake went through, let's start transferring */ 874 tf->ft->write_request( tf->ft);865 tf->ft->write_request(tf->ft); 875 866 876 867 return XT_HANDLED; 877 868 } 878 869 879 jabber_streamhost_t *jabber_si_parse_proxy( struct im_connection *ic, char *proxy)870 jabber_streamhost_t *jabber_si_parse_proxy(struct im_connection *ic, char *proxy) 880 871 { 881 872 char *host, *port, *jid; 882 873 jabber_streamhost_t *sh; 883 874 884 if( ( ( host = strchr( proxy, ',' ) ) == 0 ) || 885 ( ( port = strchr( host+1, ',' ) ) == 0 ) ) 886 { 887 imcb_log( ic, "Error parsing proxy setting: \"%s\" (ignored)", proxy ); 875 if (((host = strchr(proxy, ',')) == 0) || 876 ((port = strchr(host + 1, ',')) == 0)) { 877 imcb_log(ic, "Error parsing proxy setting: \"%s\" (ignored)", proxy); 888 878 return NULL; 889 879 } 890 880 891 881 jid = proxy; 892 882 *host++ = '\0'; 893 883 *port++ = '\0'; 894 884 895 sh = g_new0( jabber_streamhost_t, 1);896 sh->jid = g_strdup( jid);897 sh->host = g_strdup( host);898 g_snprintf( sh->port, sizeof( sh->port ), "%s", port);885 sh = g_new0(jabber_streamhost_t, 1); 886 sh->jid = g_strdup(jid); 887 sh->host = g_strdup(host); 888 g_snprintf(sh->port, sizeof(sh->port), "%s", port); 899 889 900 890 return sh; 901 891 } 902 892 903 void jabber_si_set_proxies( struct bs_transfer *bt)893 void jabber_si_set_proxies(struct bs_transfer *bt) 904 894 { 905 895 struct jabber_transfer *tf = bt->tf; 906 896 struct jabber_data *jd = tf->ic->proto_data; 907 char *proxysetting = g_strdup ( set_getstr( &tf->ic->acc->set, "proxy" ));897 char *proxysetting = g_strdup(set_getstr(&tf->ic->acc->set, "proxy")); 908 898 char *proxy, *next, *errmsg = NULL; 909 899 char port[6]; 910 char host[HOST_NAME_MAX +1];900 char host[HOST_NAME_MAX + 1]; 911 901 jabber_streamhost_t *sh, *sh2; 912 902 GSList *streamhosts = jd->streamhosts; 913 903 914 904 proxy = proxysetting; 915 while ( proxy && ( *proxy!='\0' ) ) { 916 if( ( next = strchr( proxy, ';' ) ) ) 917 *next++ = '\0'; 918 919 if( strcmp( proxy, "<local>" ) == 0 ) { 920 if( ( tf->fd = ft_listen( &tf->saddr, host, port, jd->fd, FALSE, &errmsg ) ) != -1 ) { 921 sh = g_new0( jabber_streamhost_t, 1 ); 922 sh->jid = g_strdup( tf->ini_jid ); 923 sh->host = g_strdup( host ); 924 g_snprintf( sh->port, sizeof( sh->port ), "%s", port ); 925 bt->streamhosts = g_slist_append( bt->streamhosts, sh ); 926 927 bt->tf->watch_in = b_input_add( tf->fd, B_EV_IO_READ, jabber_bs_send_handshake, bt ); 928 bt->connect_timeout = b_timeout_add( JABBER_BS_LISTEN_TIMEOUT * 1000, jabber_bs_connect_timeout, bt ); 905 while (proxy && (*proxy != '\0')) { 906 if ((next = strchr(proxy, ';'))) { 907 *next++ = '\0'; 908 } 909 910 if (strcmp(proxy, "<local>") == 0) { 911 if ((tf->fd = ft_listen(&tf->saddr, host, port, jd->fd, FALSE, &errmsg)) != -1) { 912 sh = g_new0(jabber_streamhost_t, 1); 913 sh->jid = g_strdup(tf->ini_jid); 914 sh->host = g_strdup(host); 915 g_snprintf(sh->port, sizeof(sh->port), "%s", port); 916 bt->streamhosts = g_slist_append(bt->streamhosts, sh); 917 918 bt->tf->watch_in = b_input_add(tf->fd, B_EV_IO_READ, jabber_bs_send_handshake, bt); 919 bt->connect_timeout = b_timeout_add(JABBER_BS_LISTEN_TIMEOUT * 1000, 920 jabber_bs_connect_timeout, bt); 929 921 } else { 930 imcb_log( tf->ic, "Transferring file %s: couldn't listen locally(non fatal, check your ft_listen setting in bitlbee.conf): %s", 931 tf->ft->file_name, 932 errmsg ); 922 imcb_log(tf->ic, 923 "Transferring file %s: couldn't listen locally(non fatal, check your ft_listen setting in bitlbee.conf): %s", 924 tf->ft->file_name, 925 errmsg); 933 926 } 934 } else if ( strcmp( proxy, "<auto>" ) == 0) {935 while ( streamhosts) {936 sh = g_new0( jabber_streamhost_t, 1);927 } else if (strcmp(proxy, "<auto>") == 0) { 928 while (streamhosts) { 929 sh = g_new0(jabber_streamhost_t, 1); 937 930 sh2 = streamhosts->data; 938 sh->jid = g_strdup( sh2->jid);939 sh->host = g_strdup( sh2->host);940 strcpy( sh->port, sh2->port);941 bt->streamhosts = g_slist_append( bt->streamhosts, sh);942 streamhosts = g_slist_next( streamhosts);931 sh->jid = g_strdup(sh2->jid); 932 sh->host = g_strdup(sh2->host); 933 strcpy(sh->port, sh2->port); 934 bt->streamhosts = g_slist_append(bt->streamhosts, sh); 935 streamhosts = g_slist_next(streamhosts); 943 936 } 944 } else if( ( sh = jabber_si_parse_proxy( tf->ic, proxy ) ) ) 945 bt->streamhosts = g_slist_append( bt->streamhosts, sh ); 937 } else if ((sh = jabber_si_parse_proxy(tf->ic, proxy))) { 938 bt->streamhosts = g_slist_append(bt->streamhosts, sh); 939 } 946 940 proxy = next; 947 941 } … … 951 945 * Starts a bytestream. 952 946 */ 953 gboolean jabber_bs_send_start( struct jabber_transfer *tf)947 gboolean jabber_bs_send_start(struct jabber_transfer *tf) 954 948 { 955 949 struct bs_transfer *bt; … … 957 951 char hash_hex[41]; 958 952 unsigned char hash[20]; 959 int i, ret;953 int i, ret; 960 954 961 955 /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */ 962 sha1_init( &sha ); 963 sha1_append( &sha, (unsigned char*) tf->sid, strlen( tf->sid ) ); 964 sha1_append( &sha, (unsigned char*) tf->ini_jid, strlen( tf->ini_jid ) ); 965 sha1_append( &sha, (unsigned char*) tf->tgt_jid, strlen( tf->tgt_jid ) ); 966 sha1_finish( &sha, hash ); 967 968 for( i = 0; i < 20; i ++ ) 969 sprintf( hash_hex + i * 2, "%02x", hash[i] ); 970 971 bt = g_new0( struct bs_transfer, 1 ); 956 sha1_init(&sha); 957 sha1_append(&sha, (unsigned char *) tf->sid, strlen(tf->sid)); 958 sha1_append(&sha, (unsigned char *) tf->ini_jid, strlen(tf->ini_jid)); 959 sha1_append(&sha, (unsigned char *) tf->tgt_jid, strlen(tf->tgt_jid)); 960 sha1_finish(&sha, hash); 961 962 for (i = 0; i < 20; i++) { 963 sprintf(hash_hex + i * 2, "%02x", hash[i]); 964 } 965 966 bt = g_new0(struct bs_transfer, 1); 972 967 bt->tf = tf; 973 968 bt->phase = BS_PHASE_CONNECT; 974 bt->pseudoadr = g_strdup( hash_hex);969 bt->pseudoadr = g_strdup(hash_hex); 975 970 tf->streamhandle = bt; 976 971 tf->ft->free = jabber_bs_free_transfer; 977 972 tf->ft->canceled = jabber_bs_canceled; 978 973 979 jabber_si_set_proxies( bt);980 981 ret = jabber_bs_send_request( 974 jabber_si_set_proxies(bt); 975 976 ret = jabber_bs_send_request(tf, bt->streamhosts); 982 977 983 978 return ret; 984 979 } 985 980 986 gboolean jabber_bs_send_request( struct jabber_transfer *tf, GSList *streamhosts)981 gboolean jabber_bs_send_request(struct jabber_transfer *tf, GSList *streamhosts) 987 982 { 988 983 struct xt_node *shnode, *query, *iq; 989 984 990 query = xt_new_node( "query", NULL, NULL);991 xt_add_attr( query, "xmlns", XMLNS_BYTESTREAMS);992 xt_add_attr( query, "sid", tf->sid);993 xt_add_attr( query, "mode", "tcp");994 995 while ( streamhosts) {985 query = xt_new_node("query", NULL, NULL); 986 xt_add_attr(query, "xmlns", XMLNS_BYTESTREAMS); 987 xt_add_attr(query, "sid", tf->sid); 988 xt_add_attr(query, "mode", "tcp"); 989 990 while (streamhosts) { 996 991 jabber_streamhost_t *sh = streamhosts->data; 997 shnode = xt_new_node( "streamhost", NULL, NULL ); 998 xt_add_attr( shnode, "jid", sh->jid ); 999 xt_add_attr( shnode, "host", sh->host ); 1000 xt_add_attr( shnode, "port", sh->port ); 1001 1002 xt_add_child( query, shnode ); 1003 1004 streamhosts = g_slist_next( streamhosts ); 1005 } 1006 1007 1008 iq = jabber_make_packet( "iq", "set", tf->tgt_jid, query ); 1009 xt_add_attr( iq, "from", tf->ini_jid ); 1010 1011 jabber_cache_add( tf->ic, iq, jabber_bs_send_handle_reply ); 1012 1013 if( !jabber_write_packet( tf->ic, iq ) ) 1014 imcb_file_canceled( tf->ic, tf->ft, "Error transmitting bytestream request" ); 992 shnode = xt_new_node("streamhost", NULL, NULL); 993 xt_add_attr(shnode, "jid", sh->jid); 994 xt_add_attr(shnode, "host", sh->host); 995 xt_add_attr(shnode, "port", sh->port); 996 997 xt_add_child(query, shnode); 998 999 streamhosts = g_slist_next(streamhosts); 1000 } 1001 1002 1003 iq = jabber_make_packet("iq", "set", tf->tgt_jid, query); 1004 xt_add_attr(iq, "from", tf->ini_jid); 1005 1006 jabber_cache_add(tf->ic, iq, jabber_bs_send_handle_reply); 1007 1008 if (!jabber_write_packet(tf->ic, iq)) { 1009 imcb_file_canceled(tf->ic, tf->ft, "Error transmitting bytestream request"); 1010 } 1015 1011 return TRUE; 1016 1012 } 1017 1013 1018 gboolean jabber_bs_send_handshake_abort(struct bs_transfer *bt, char *error 1014 gboolean jabber_bs_send_handshake_abort(struct bs_transfer *bt, char *error) 1019 1015 { 1020 1016 struct jabber_transfer *tf = bt->tf; … … 1022 1018 1023 1019 /* TODO: did the receiver get here somehow??? */ 1024 imcb_log( tf->ic, "Transferring file %s: SOCKS5 handshake failed: %s", 1025 tf->ft->file_name, 1026 error ); 1027 1028 if( jd->streamhosts==NULL ) /* we're done here unless we have a proxy to try */ 1029 imcb_file_canceled( tf->ic, tf->ft, error ); 1020 imcb_log(tf->ic, "Transferring file %s: SOCKS5 handshake failed: %s", 1021 tf->ft->file_name, 1022 error); 1023 1024 if (jd->streamhosts == NULL) { /* we're done here unless we have a proxy to try */ 1025 imcb_file_canceled(tf->ic, tf->ft, error); 1026 } 1030 1027 1031 1028 /* MUST always return FALSE! */ … … 1036 1033 * SOCKS5BYTESTREAM protocol for the sender 1037 1034 */ 1038 gboolean jabber_bs_send_handshake( gpointer data, gint fd, b_input_condition cond)1035 gboolean jabber_bs_send_handshake(gpointer data, gint fd, b_input_condition cond) 1039 1036 { 1040 1037 struct bs_transfer *bt = data; … … 1042 1039 short revents; 1043 1040 1044 if ( !jabber_bs_poll( bt, fd, &revents ) )1041 if (!jabber_bs_poll(bt, fd, &revents)) { 1045 1042 return FALSE; 1046 1047 switch( bt->phase ) 1043 } 1044 1045 switch (bt->phase) { 1046 case BS_PHASE_CONNECT: 1048 1047 { 1049 case BS_PHASE_CONNECT: 1050 { 1051 struct sockaddr_storage clt_addr; 1052 socklen_t ssize = sizeof( clt_addr ); 1053 1054 /* Connect */ 1055 1056 ASSERTSOCKOP( tf->fd = accept( fd, (struct sockaddr *) &clt_addr, &ssize ), "Accepting connection" ); 1057 1058 closesocket( fd ); 1059 fd = tf->fd; 1060 sock_make_nonblocking( fd ); 1061 1062 bt->phase = BS_PHASE_CONNECTED; 1063 1064 bt->tf->watch_in = b_input_add( fd, B_EV_IO_READ, jabber_bs_send_handshake, bt ); 1048 struct sockaddr_storage clt_addr; 1049 socklen_t ssize = sizeof(clt_addr); 1050 1051 /* Connect */ 1052 1053 ASSERTSOCKOP(tf->fd = accept(fd, (struct sockaddr *) &clt_addr, &ssize), "Accepting connection"); 1054 1055 closesocket(fd); 1056 fd = tf->fd; 1057 sock_make_nonblocking(fd); 1058 1059 bt->phase = BS_PHASE_CONNECTED; 1060 1061 bt->tf->watch_in = b_input_add(fd, B_EV_IO_READ, jabber_bs_send_handshake, bt); 1062 return FALSE; 1063 } 1064 case BS_PHASE_CONNECTED: 1065 { 1066 int ret, have_noauth = FALSE; 1067 struct { 1068 unsigned char ver; 1069 unsigned char method; 1070 } socks5_auth_reply = { .ver = 5, .method = 0 }; 1071 struct { 1072 unsigned char ver; 1073 unsigned char nmethods; 1074 unsigned char method; 1075 } socks5_hello; 1076 1077 if (!(ret = jabber_bs_peek(bt, &socks5_hello, sizeof(socks5_hello)))) { 1065 1078 return FALSE; 1066 1079 } 1067 case BS_PHASE_CONNECTED: 1068 { 1069 int ret, have_noauth=FALSE; 1070 struct { 1071 unsigned char ver; 1072 unsigned char method; 1073 } socks5_auth_reply = { .ver = 5, .method = 0 }; 1074 struct { 1075 unsigned char ver; 1076 unsigned char nmethods; 1077 unsigned char method; 1078 } socks5_hello; 1079 1080 if( !( ret = jabber_bs_peek( bt, &socks5_hello, sizeof( socks5_hello ) ) ) ) 1081 return FALSE; 1082 1083 if( ret < sizeof( socks5_hello ) ) 1084 return TRUE; 1085 1086 if( !( socks5_hello.ver == 5 ) || 1087 !( socks5_hello.nmethods >= 1 ) || 1088 !( socks5_hello.nmethods < 32 ) ) 1089 return jabber_bs_abort( bt, "Invalid auth request ver=%d nmethods=%d method=%d", socks5_hello.ver, socks5_hello.nmethods, socks5_hello.method ); 1090 1091 have_noauth = socks5_hello.method == 0; 1092 1093 if( socks5_hello.nmethods > 1 ) 1094 { 1095 char mbuf[32]; 1096 int i; 1097 ASSERTSOCKOP( ret = recv( fd, mbuf, socks5_hello.nmethods - 1, 0 ) , "Receiving auth methods" ); 1098 if( ret < ( socks5_hello.nmethods - 1 ) ) 1099 return jabber_bs_abort( bt, "Partial auth request"); 1100 for( i = 0 ; !have_noauth && ( i < socks5_hello.nmethods - 1 ) ; i ++ ) 1101 if( mbuf[i] == 0 ) 1102 have_noauth = TRUE; 1080 1081 if (ret < sizeof(socks5_hello)) { 1082 return TRUE; 1083 } 1084 1085 if (!(socks5_hello.ver == 5) || 1086 !(socks5_hello.nmethods >= 1) || 1087 !(socks5_hello.nmethods < 32)) { 1088 return jabber_bs_abort(bt, "Invalid auth request ver=%d nmethods=%d method=%d", 1089 socks5_hello.ver, socks5_hello.nmethods, socks5_hello.method); 1090 } 1091 1092 have_noauth = socks5_hello.method == 0; 1093 1094 if (socks5_hello.nmethods > 1) { 1095 char mbuf[32]; 1096 int i; 1097 ASSERTSOCKOP(ret = recv(fd, mbuf, socks5_hello.nmethods - 1, 0), "Receiving auth methods"); 1098 if (ret < (socks5_hello.nmethods - 1)) { 1099 return jabber_bs_abort(bt, "Partial auth request"); 1103 1100 } 1104 1105 if( !have_noauth ) 1106 return jabber_bs_abort( bt, "Auth request didn't include no authentication" ); 1107 1108 ASSERTSOCKOP( send( fd, &socks5_auth_reply, sizeof( socks5_auth_reply ) , 0 ), "Sending auth reply" ); 1109 1110 bt->phase = BS_PHASE_REQUEST; 1111 1101 for (i = 0; !have_noauth && (i < socks5_hello.nmethods - 1); i++) { 1102 if (mbuf[i] == 0) { 1103 have_noauth = TRUE; 1104 } 1105 } 1106 } 1107 1108 if (!have_noauth) { 1109 return jabber_bs_abort(bt, "Auth request didn't include no authentication"); 1110 } 1111 1112 ASSERTSOCKOP(send(fd, &socks5_auth_reply, sizeof(socks5_auth_reply), 0), "Sending auth reply"); 1113 1114 bt->phase = BS_PHASE_REQUEST; 1115 1116 return TRUE; 1117 } 1118 case BS_PHASE_REQUEST: 1119 { 1120 struct socks5_message socks5_connect; 1121 int msgsize = sizeof(struct socks5_message); 1122 int ret; 1123 1124 if (!(ret = jabber_bs_peek(bt, &socks5_connect, msgsize))) { 1125 return FALSE; 1126 } 1127 1128 if (ret < msgsize) { 1112 1129 return TRUE; 1113 1130 } 1114 case BS_PHASE_REQUEST: 1115 { 1116 struct socks5_message socks5_connect; 1117 int msgsize = sizeof( struct socks5_message ); 1118 int ret; 1119 1120 if( !( ret = jabber_bs_peek( bt, &socks5_connect, msgsize ) ) ) 1121 return FALSE; 1122 1123 if( ret < msgsize ) 1124 return TRUE; 1125 1126 if( !( socks5_connect.ver == 5) || 1127 !( socks5_connect.cmdrep.cmd == 1 ) || 1128 !( socks5_connect.atyp == 3 ) || 1129 !(socks5_connect.addrlen == 40 ) ) 1130 return jabber_bs_abort( bt, "Invalid SOCKS5 Connect message (addrlen=%d, ver=%d, cmd=%d, atyp=%d)", socks5_connect.addrlen, socks5_connect.ver, socks5_connect.cmdrep.cmd, socks5_connect.atyp ); 1131 if( !( memcmp( socks5_connect.address, bt->pseudoadr, 40 ) == 0 ) ) 1132 return jabber_bs_abort( bt, "SOCKS5 Connect message contained wrong digest"); 1133 1134 socks5_connect.cmdrep.rep = 0; 1135 1136 ASSERTSOCKOP( send( fd, &socks5_connect, msgsize, 0 ), "Sending connect reply" ); 1137 1138 bt->phase = BS_PHASE_REPLY; 1139 1140 imcb_log( tf->ic, "File %s: SOCKS5 handshake successful! Transfer about to start...", tf->ft->file_name ); 1141 1142 if( tf->accepted ) 1143 { 1144 /* streamhost-used message came already in(possible?), let's start sending */ 1145 tf->ft->write_request( tf->ft ); 1146 } 1147 1148 tf->watch_in = 0; 1149 return FALSE; 1150 1151 } 1131 1132 if (!(socks5_connect.ver == 5) || 1133 !(socks5_connect.cmdrep.cmd == 1) || 1134 !(socks5_connect.atyp == 3) || 1135 !(socks5_connect.addrlen == 40)) { 1136 return jabber_bs_abort(bt, 1137 "Invalid SOCKS5 Connect message (addrlen=%d, ver=%d, cmd=%d, atyp=%d)", 1138 socks5_connect.addrlen, socks5_connect.ver, socks5_connect.cmdrep.cmd, 1139 socks5_connect.atyp); 1140 } 1141 if (!(memcmp(socks5_connect.address, bt->pseudoadr, 40) == 0)) { 1142 return jabber_bs_abort(bt, "SOCKS5 Connect message contained wrong digest"); 1143 } 1144 1145 socks5_connect.cmdrep.rep = 0; 1146 1147 ASSERTSOCKOP(send(fd, &socks5_connect, msgsize, 0), "Sending connect reply"); 1148 1149 bt->phase = BS_PHASE_REPLY; 1150 1151 imcb_log(tf->ic, "File %s: SOCKS5 handshake successful! Transfer about to start...", tf->ft->file_name); 1152 1153 if (tf->accepted) { 1154 /* streamhost-used message came already in(possible?), let's start sending */ 1155 tf->ft->write_request(tf->ft); 1156 } 1157 1158 tf->watch_in = 0; 1159 return FALSE; 1160 1161 } 1152 1162 default: 1153 1163 /* BUG */ 1154 imcb_log( bt->tf->ic, "BUG in file transfer code: undefined handshake phase");1164 imcb_log(bt->tf->ic, "BUG in file transfer code: undefined handshake phase"); 1155 1165 1156 1166 bt->tf->watch_in = 0; -
protocols/jabber/sasl.c
raf359b4 r5ebff60 48 48 }; 49 49 50 xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data)50 xt_status sasl_pkt_mechanisms(struct xt_node *node, gpointer data) 51 51 { 52 52 struct im_connection *ic = data; … … 57 57 int want_oauth = FALSE; 58 58 GString *mechs; 59 60 if( !sasl_supported( ic ) ) 61 { 59 60 if (!sasl_supported(ic)) { 62 61 /* Should abort this now, since we should already be doing 63 62 IQ authentication. Strange things happen when you try 64 63 to do both... */ 65 imcb_log( ic, "XMPP 1.0 non-compliant server seems to support SASL, please report this as a BitlBee bug!" ); 64 imcb_log(ic, 65 "XMPP 1.0 non-compliant server seems to support SASL, please report this as a BitlBee bug!"); 66 66 return XT_HANDLED; 67 67 } 68 69 s = xt_find_attr( node, "xmlns" ); 70 if( !s || strcmp( s, XMLNS_SASL ) != 0 ) 71 { 72 imcb_log( ic, "Stream error while authenticating" ); 73 imc_logout( ic, FALSE ); 68 69 s = xt_find_attr(node, "xmlns"); 70 if (!s || strcmp(s, XMLNS_SASL) != 0) { 71 imcb_log(ic, "Stream error while authenticating"); 72 imc_logout(ic, FALSE); 74 73 return XT_ABORT; 75 74 } 76 77 want_oauth = set_getbool( &ic->acc->set, "oauth");78 79 mechs = g_string_new( "");75 76 want_oauth = set_getbool(&ic->acc->set, "oauth"); 77 78 mechs = g_string_new(""); 80 79 c = node->children; 81 while( ( c = xt_find_node( c, "mechanism" ) ) ) 82 { 83 if( c->text && g_strcasecmp( c->text, "PLAIN" ) == 0 ) 80 while ((c = xt_find_node(c, "mechanism"))) { 81 if (c->text && g_strcasecmp(c->text, "PLAIN") == 0) { 84 82 sup_plain = 1; 85 else if( c->text && g_strcasecmp( c->text, "DIGEST-MD5" ) == 0 )83 } else if (c->text && g_strcasecmp(c->text, "DIGEST-MD5") == 0) { 86 84 sup_digest = 1; 87 else if( c->text && g_strcasecmp( c->text, "X-OAUTH2" ) == 0 )85 } else if (c->text && g_strcasecmp(c->text, "X-OAUTH2") == 0) { 88 86 sup_gtalk = 1; 89 else if( c->text && g_strcasecmp( c->text, "X-FACEBOOK-PLATFORM" ) == 0 )87 } else if (c->text && g_strcasecmp(c->text, "X-FACEBOOK-PLATFORM") == 0) { 90 88 sup_fb = 1; 91 92 if( c->text ) 93 g_string_append_printf( mechs, " %s", c->text ); 94 89 } 90 91 if (c->text) { 92 g_string_append_printf(mechs, " %s", c->text); 93 } 94 95 95 c = c->next; 96 96 } 97 98 if ( !want_oauth && !sup_plain && !sup_digest )99 {100 if( !sup_gtalk && !sup_fb )101 imcb_error( ic, "This server requires OAuth "102 "(supported schemes:%s)", mechs->str );103 else104 imcb_error( ic, "BitlBee does not support any of the offered SASL "105 "authentication schemes:%s", mechs->str );106 imc_logout( ic, FALSE);107 g_string_free( mechs, TRUE);97 98 if (!want_oauth && !sup_plain && !sup_digest) { 99 if (!sup_gtalk && !sup_fb) { 100 imcb_error(ic, "This server requires OAuth " 101 "(supported schemes:%s)", mechs->str); 102 } else { 103 imcb_error(ic, "BitlBee does not support any of the offered SASL " 104 "authentication schemes:%s", mechs->str); 105 } 106 imc_logout(ic, FALSE); 107 g_string_free(mechs, TRUE); 108 108 return XT_ABORT; 109 109 } 110 g_string_free( mechs, TRUE ); 111 112 reply = xt_new_node( "auth", NULL, NULL ); 113 xt_add_attr( reply, "xmlns", XMLNS_SASL ); 114 115 if( sup_gtalk && want_oauth ) 116 { 110 g_string_free(mechs, TRUE); 111 112 reply = xt_new_node("auth", NULL, NULL); 113 xt_add_attr(reply, "xmlns", XMLNS_SASL); 114 115 if (sup_gtalk && want_oauth) { 117 116 int len; 118 117 119 118 /* X-OAUTH2 is, not *the* standard OAuth2 SASL/XMPP implementation. 120 119 It's currently used by GTalk and vaguely documented on 121 120 http://code.google.com/apis/cloudprint/docs/rawxmpp.html . */ 122 xt_add_attr( reply, "mechanism", "X-OAUTH2");123 124 len = strlen( jd->username ) + strlen( jd->oauth2_access_token) + 2;125 s = g_malloc( len + 1);121 xt_add_attr(reply, "mechanism", "X-OAUTH2"); 122 123 len = strlen(jd->username) + strlen(jd->oauth2_access_token) + 2; 124 s = g_malloc(len + 1); 126 125 s[0] = 0; 127 strcpy( s + 1, jd->username ); 128 strcpy( s + 2 + strlen( jd->username ), jd->oauth2_access_token ); 129 reply->text = base64_encode( (unsigned char *)s, len ); 130 reply->text_len = strlen( reply->text ); 131 g_free( s ); 132 } 133 else if( sup_fb && want_oauth ) 134 { 135 xt_add_attr( reply, "mechanism", "X-FACEBOOK-PLATFORM" ); 126 strcpy(s + 1, jd->username); 127 strcpy(s + 2 + strlen(jd->username), jd->oauth2_access_token); 128 reply->text = base64_encode((unsigned char *) s, len); 129 reply->text_len = strlen(reply->text); 130 g_free(s); 131 } else if (sup_fb && want_oauth) { 132 xt_add_attr(reply, "mechanism", "X-FACEBOOK-PLATFORM"); 136 133 jd->flags |= JFLAG_SASL_FB; 137 } 138 else if( want_oauth ) 139 { 140 imcb_error( ic, "OAuth requested, but not supported by server" ); 141 imc_logout( ic, FALSE ); 142 xt_free_node( reply ); 134 } else if (want_oauth) { 135 imcb_error(ic, "OAuth requested, but not supported by server"); 136 imc_logout(ic, FALSE); 137 xt_free_node(reply); 143 138 return XT_ABORT; 144 } 145 else if( sup_digest ) 146 { 147 xt_add_attr( reply, "mechanism", "DIGEST-MD5" ); 148 139 } else if (sup_digest) { 140 xt_add_attr(reply, "mechanism", "DIGEST-MD5"); 141 149 142 /* The rest will be done later, when we receive a <challenge/>. */ 150 } 151 else if( sup_plain ) 152 { 143 } else if (sup_plain) { 153 144 int len; 154 155 xt_add_attr( reply, "mechanism", "PLAIN");156 145 146 xt_add_attr(reply, "mechanism", "PLAIN"); 147 157 148 /* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */ 158 len = strlen( jd->username ) + strlen( ic->acc->pass) + 2;159 s = g_malloc( len + 1);149 len = strlen(jd->username) + strlen(ic->acc->pass) + 2; 150 s = g_malloc(len + 1); 160 151 s[0] = 0; 161 strcpy( s + 1, jd->username ); 162 strcpy( s + 2 + strlen( jd->username ), ic->acc->pass ); 163 reply->text = base64_encode( (unsigned char *)s, len ); 164 reply->text_len = strlen( reply->text ); 165 g_free( s ); 166 } 167 168 if( reply && !jabber_write_packet( ic, reply ) ) 169 { 170 xt_free_node( reply ); 152 strcpy(s + 1, jd->username); 153 strcpy(s + 2 + strlen(jd->username), ic->acc->pass); 154 reply->text = base64_encode((unsigned char *) s, len); 155 reply->text_len = strlen(reply->text); 156 g_free(s); 157 } 158 159 if (reply && !jabber_write_packet(ic, reply)) { 160 xt_free_node(reply); 171 161 return XT_ABORT; 172 162 } 173 xt_free_node( reply);174 163 xt_free_node(reply); 164 175 165 /* To prevent classic authentication from happening. */ 176 166 jd->flags |= JFLAG_STREAM_STARTED; 177 167 178 168 return XT_HANDLED; 179 169 } … … 181 171 /* Non-static function, but not mentioned in jabber.h because it's for internal 182 172 use, just that the unittest should be able to reach it... */ 183 char *sasl_get_part( char *data, char *field)173 char *sasl_get_part(char *data, char *field) 184 174 { 185 175 int i, len; 186 187 len = strlen( field ); 188 189 while( g_ascii_isspace( *data ) || *data == ',' ) 190 data ++; 191 192 if( g_strncasecmp( data, field, len ) == 0 && data[len] == '=' ) 193 { 194 i = strlen( field ) + 1; 195 } 196 else 197 { 198 for( i = 0; data[i]; i ++ ) 199 { 176 177 len = strlen(field); 178 179 while (g_ascii_isspace(*data) || *data == ',') { 180 data++; 181 } 182 183 if (g_strncasecmp(data, field, len) == 0 && data[len] == '=') { 184 i = strlen(field) + 1; 185 } else { 186 for (i = 0; data[i]; i++) { 200 187 /* If we have a ", skip until it's closed again. */ 201 if ( data[i] == '"' )202 {203 i ++;204 while( data[i] != '"' || data[i-1] == '\\' )205 i ++;188 if (data[i] == '"') { 189 i++; 190 while (data[i] != '"' || data[i - 1] == '\\') { 191 i++; 192 } 206 193 } 207 194 208 195 /* If we got a comma, we got a new field. Check it, 209 196 find the next key after it. */ 210 if( data[i] == ',' ) 211 { 212 while( g_ascii_isspace( data[i] ) || data[i] == ',' ) 213 i ++; 214 215 if( g_strncasecmp( data + i, field, len ) == 0 && 216 data[i+len] == '=' ) 217 { 197 if (data[i] == ',') { 198 while (g_ascii_isspace(data[i]) || data[i] == ',') { 199 i++; 200 } 201 202 if (g_strncasecmp(data + i, field, len) == 0 && 203 data[i + len] == '=') { 218 204 i += len + 1; 219 205 break; … … 222 208 } 223 209 } 224 225 if( data[i] == '"' ) 226 { 210 211 if (data[i] == '"') { 227 212 int j; 228 213 char *ret; 229 230 i 214 215 i++; 231 216 len = 0; 232 while( data[i+len] != '"' || data[i+len-1] == '\\' ) 233 len ++; 234 235 ret = g_strndup( data + i, len ); 236 for( i = j = 0; ret[i]; i ++ ) 237 { 238 if( ret[i] == '\\' ) 239 { 217 while (data[i + len] != '"' || data[i + len - 1] == '\\') { 218 len++; 219 } 220 221 ret = g_strndup(data + i, len); 222 for (i = j = 0; ret[i]; i++) { 223 if (ret[i] == '\\') { 240 224 ret[j++] = ret[++i]; 241 } 242 else 243 { 225 } else { 244 226 ret[j++] = ret[i]; 245 227 } 246 228 } 247 229 ret[j] = 0; 248 230 249 231 return ret; 250 } 251 else if( data[i] ) 252 { 232 } else if (data[i]) { 253 233 len = 0; 254 while( data[i+len] && data[i+len] != ',' ) 255 len ++; 256 257 return g_strndup( data + i, len ); 258 } 259 else 260 { 234 while (data[i + len] && data[i + len] != ',') { 235 len++; 236 } 237 238 return g_strndup(data + i, len); 239 } else { 261 240 return NULL; 262 241 } 263 242 } 264 243 265 xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data)244 xt_status sasl_pkt_challenge(struct xt_node *node, gpointer data) 266 245 { 267 246 struct im_connection *ic = data; … … 274 253 char *s = NULL, *reply = NULL; 275 254 xt_status ret = XT_ABORT; 276 277 if ( node->text_len == 0 )255 256 if (node->text_len == 0) { 278 257 goto error; 279 280 dec = frombase64( node->text ); 281 282 if( jd->flags & JFLAG_SASL_FB ) 283 {258 } 259 260 dec = frombase64(node->text); 261 262 if (jd->flags & JFLAG_SASL_FB) { 284 263 /* New-style Facebook OAauth2 support. Instead of sending a refresh 285 264 token, they just send an access token that should never expire. */ 286 265 GSList *p_in = NULL, *p_out = NULL; 287 266 char time[33]; 288 289 oauth_params_parse( &p_in, dec ); 290 oauth_params_add( &p_out, "nonce", oauth_params_get( &p_in, "nonce" ) ); 291 oauth_params_add( &p_out, "method", oauth_params_get( &p_in, "method" ) ); 292 oauth_params_free( &p_in ); 293 294 g_snprintf( time, sizeof( time ), "%lld", (long long) ( gettime() * 1000 ) ); 295 oauth_params_add( &p_out, "call_id", time ); 296 oauth_params_add( &p_out, "api_key", oauth2_service_facebook.consumer_key ); 297 oauth_params_add( &p_out, "v", "1.0" ); 298 oauth_params_add( &p_out, "format", "XML" ); 299 oauth_params_add( &p_out, "access_token", jd->oauth2_access_token ); 300 301 reply = oauth_params_string( p_out ); 302 oauth_params_free( &p_out ); 303 } 304 else if( !( s = sasl_get_part( dec, "rspauth" ) ) ) 305 { 267 268 oauth_params_parse(&p_in, dec); 269 oauth_params_add(&p_out, "nonce", oauth_params_get(&p_in, "nonce")); 270 oauth_params_add(&p_out, "method", oauth_params_get(&p_in, "method")); 271 oauth_params_free(&p_in); 272 273 g_snprintf(time, sizeof(time), "%lld", (long long) (gettime() * 1000)); 274 oauth_params_add(&p_out, "call_id", time); 275 oauth_params_add(&p_out, "api_key", oauth2_service_facebook.consumer_key); 276 oauth_params_add(&p_out, "v", "1.0"); 277 oauth_params_add(&p_out, "format", "XML"); 278 oauth_params_add(&p_out, "access_token", jd->oauth2_access_token); 279 280 reply = oauth_params_string(p_out); 281 oauth_params_free(&p_out); 282 } else if (!(s = sasl_get_part(dec, "rspauth"))) { 306 283 /* See RFC 2831 for for information. */ 307 284 md5_state_t A1, A2, H; … … 309 286 char A1h[33], A2h[33], Hh[33]; 310 287 int i; 311 312 nonce = sasl_get_part( dec, "nonce");313 realm = sasl_get_part( dec, "realm");314 315 if ( !nonce )288 289 nonce = sasl_get_part(dec, "nonce"); 290 realm = sasl_get_part(dec, "realm"); 291 292 if (!nonce) { 316 293 goto error; 317 294 } 295 318 296 /* Jabber.Org considers the realm part optional and doesn't 319 297 specify one. Oh well, actually they're right, but still, 320 298 don't know if this is right... */ 321 if( !realm ) 322 realm = g_strdup( jd->server ); 323 324 random_bytes( cnonce_bin, sizeof( cnonce_bin ) ); 325 cnonce = base64_encode( cnonce_bin, sizeof( cnonce_bin ) ); 326 digest_uri = g_strdup_printf( "%s/%s", "xmpp", jd->server ); 327 299 if (!realm) { 300 realm = g_strdup(jd->server); 301 } 302 303 random_bytes(cnonce_bin, sizeof(cnonce_bin)); 304 cnonce = base64_encode(cnonce_bin, sizeof(cnonce_bin)); 305 digest_uri = g_strdup_printf("%s/%s", "xmpp", jd->server); 306 328 307 /* Generate the MD5 hash of username:realm:password, 329 308 I decided to call it H. */ 330 md5_init( &H);331 s = g_strdup_printf( "%s:%s:%s", jd->username, realm, ic->acc->pass);332 md5_append( &H, (unsigned char *) s, strlen( s ));333 g_free( s);334 md5_finish( &H, Hr);335 309 md5_init(&H); 310 s = g_strdup_printf("%s:%s:%s", jd->username, realm, ic->acc->pass); 311 md5_append(&H, (unsigned char *) s, strlen(s)); 312 g_free(s); 313 md5_finish(&H, Hr); 314 336 315 /* Now generate the hex. MD5 hash of H:nonce:cnonce, called A1. */ 337 md5_init( &A1 ); 338 s = g_strdup_printf( ":%s:%s", nonce, cnonce ); 339 md5_append( &A1, Hr, 16 ); 340 md5_append( &A1, (unsigned char *) s, strlen( s ) ); 341 g_free( s ); 342 md5_finish( &A1, A1r ); 343 for( i = 0; i < 16; i ++ ) 344 sprintf( A1h + i * 2, "%02x", A1r[i] ); 345 316 md5_init(&A1); 317 s = g_strdup_printf(":%s:%s", nonce, cnonce); 318 md5_append(&A1, Hr, 16); 319 md5_append(&A1, (unsigned char *) s, strlen(s)); 320 g_free(s); 321 md5_finish(&A1, A1r); 322 for (i = 0; i < 16; i++) { 323 sprintf(A1h + i * 2, "%02x", A1r[i]); 324 } 325 346 326 /* A2... */ 347 md5_init( &A2 ); 348 s = g_strdup_printf( "%s:%s", "AUTHENTICATE", digest_uri ); 349 md5_append( &A2, (unsigned char *) s, strlen( s ) ); 350 g_free( s ); 351 md5_finish( &A2, A2r ); 352 for( i = 0; i < 16; i ++ ) 353 sprintf( A2h + i * 2, "%02x", A2r[i] ); 354 327 md5_init(&A2); 328 s = g_strdup_printf("%s:%s", "AUTHENTICATE", digest_uri); 329 md5_append(&A2, (unsigned char *) s, strlen(s)); 330 g_free(s); 331 md5_finish(&A2, A2r); 332 for (i = 0; i < 16; i++) { 333 sprintf(A2h + i * 2, "%02x", A2r[i]); 334 } 335 355 336 /* Final result: A1:nonce:00000001:cnonce:auth:A2. Let's reuse H for it. */ 356 md5_init( &H ); 357 s = g_strdup_printf( "%s:%s:%s:%s:%s:%s", A1h, nonce, "00000001", cnonce, "auth", A2h ); 358 md5_append( &H, (unsigned char *) s, strlen( s ) ); 359 g_free( s ); 360 md5_finish( &H, Hr ); 361 for( i = 0; i < 16; i ++ ) 362 sprintf( Hh + i * 2, "%02x", Hr[i] ); 363 337 md5_init(&H); 338 s = g_strdup_printf("%s:%s:%s:%s:%s:%s", A1h, nonce, "00000001", cnonce, "auth", A2h); 339 md5_append(&H, (unsigned char *) s, strlen(s)); 340 g_free(s); 341 md5_finish(&H, Hr); 342 for (i = 0; i < 16; i++) { 343 sprintf(Hh + i * 2, "%02x", Hr[i]); 344 } 345 364 346 /* Now build the SASL response string: */ 365 reply = g_strdup_printf( "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\"," 366 "nc=%08x,qop=auth,digest-uri=\"%s\",response=%s,charset=%s", 367 jd->username, realm, nonce, cnonce, 1, digest_uri, Hh, "utf-8" ); 368 } 369 else 370 { 347 reply = g_strdup_printf("username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\"," 348 "nc=%08x,qop=auth,digest-uri=\"%s\",response=%s,charset=%s", 349 jd->username, realm, nonce, cnonce, 1, digest_uri, Hh, "utf-8"); 350 } else { 371 351 /* We found rspauth, but don't really care... */ 372 g_free( s);373 } 374 375 s = reply ? tobase64( reply) : NULL;376 reply_pkt = xt_new_node( "response", s, NULL);377 xt_add_attr( reply_pkt, "xmlns", XMLNS_SASL);378 379 if ( !jabber_write_packet( ic, reply_pkt ) )352 g_free(s); 353 } 354 355 s = reply ? tobase64(reply) : NULL; 356 reply_pkt = xt_new_node("response", s, NULL); 357 xt_add_attr(reply_pkt, "xmlns", XMLNS_SASL); 358 359 if (!jabber_write_packet(ic, reply_pkt)) { 380 360 goto silent_error; 381 361 } 362 382 363 ret = XT_HANDLED; 383 364 goto silent_error; 384 365 385 366 error: 386 imcb_error( ic, "Incorrect SASL challenge received");387 imc_logout( ic, FALSE);367 imcb_error(ic, "Incorrect SASL challenge received"); 368 imc_logout(ic, FALSE); 388 369 389 370 silent_error: 390 g_free( digest_uri);391 g_free( cnonce);392 g_free( nonce);393 g_free( reply);394 g_free( realm);395 g_free( dec);396 g_free( s);397 xt_free_node( reply_pkt);398 371 g_free(digest_uri); 372 g_free(cnonce); 373 g_free(nonce); 374 g_free(reply); 375 g_free(realm); 376 g_free(dec); 377 g_free(s); 378 xt_free_node(reply_pkt); 379 399 380 return ret; 400 381 } 401 382 402 xt_status sasl_pkt_result( struct xt_node *node, gpointer data)383 xt_status sasl_pkt_result(struct xt_node *node, gpointer data) 403 384 { 404 385 struct im_connection *ic = data; 405 386 struct jabber_data *jd = ic->proto_data; 406 387 char *s; 407 408 s = xt_find_attr( node, "xmlns" ); 409 if( !s || strcmp( s, XMLNS_SASL ) != 0 ) 410 { 411 imcb_log( ic, "Stream error while authenticating" ); 412 imc_logout( ic, FALSE ); 388 389 s = xt_find_attr(node, "xmlns"); 390 if (!s || strcmp(s, XMLNS_SASL) != 0) { 391 imcb_log(ic, "Stream error while authenticating"); 392 imc_logout(ic, FALSE); 413 393 return XT_ABORT; 414 394 } 415 416 if( strcmp( node->name, "success" ) == 0 ) 417 { 418 imcb_log( ic, "Authentication finished" ); 395 396 if (strcmp(node->name, "success") == 0) { 397 imcb_log(ic, "Authentication finished"); 419 398 jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART; 420 } 421 else if( strcmp( node->name, "failure" ) == 0 ) 422 { 423 imcb_error( ic, "Authentication failure" ); 424 imc_logout( ic, FALSE ); 399 } else if (strcmp(node->name, "failure") == 0) { 400 imcb_error(ic, "Authentication failure"); 401 imc_logout(ic, FALSE); 425 402 return XT_ABORT; 426 403 } 427 404 428 405 return XT_HANDLED; 429 406 } … … 432 409 It's done by checking if the <stream:stream> from the server has a 433 410 version attribute. I don't know if this is the right way though... */ 434 gboolean sasl_supported( struct im_connection *ic)435 { 436 struct jabber_data *jd = ic->proto_data; 437 438 return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" )) != 0;439 } 440 441 void sasl_oauth2_init( struct im_connection *ic)411 gboolean sasl_supported(struct im_connection *ic) 412 { 413 struct jabber_data *jd = ic->proto_data; 414 415 return (jd->xt && jd->xt->root && xt_find_attr(jd->xt->root, "version")) != 0; 416 } 417 418 void sasl_oauth2_init(struct im_connection *ic) 442 419 { 443 420 struct jabber_data *jd = ic->proto_data; 444 421 char *msg, *url; 445 446 imcb_log( ic, "Starting OAuth authentication");447 422 423 imcb_log(ic, "Starting OAuth authentication"); 424 448 425 /* Temporary contact, just used to receive the OAuth response. */ 449 imcb_add_buddy( ic, JABBER_OAUTH_HANDLE, NULL);450 url = oauth2_url( jd->oauth2_service);451 msg = g_strdup_printf( "Open this URL in your browser to authenticate: %s", url);452 imcb_buddy_msg( ic, JABBER_OAUTH_HANDLE, msg, 0, 0);453 imcb_buddy_msg( 454 "authorization token.", 0, 0);455 456 g_free( msg);457 g_free( url);458 } 459 460 static gboolean sasl_oauth2_remove_contact( gpointer data, gint fd, b_input_condition cond)426 imcb_add_buddy(ic, JABBER_OAUTH_HANDLE, NULL); 427 url = oauth2_url(jd->oauth2_service); 428 msg = g_strdup_printf("Open this URL in your browser to authenticate: %s", url); 429 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, msg, 0, 0); 430 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, "Respond to this message with the returned " 431 "authorization token.", 0, 0); 432 433 g_free(msg); 434 g_free(url); 435 } 436 437 static gboolean sasl_oauth2_remove_contact(gpointer data, gint fd, b_input_condition cond) 461 438 { 462 439 struct im_connection *ic = data; 463 if( g_slist_find( jabber_connections, ic ) ) 464 imcb_remove_buddy( ic, JABBER_OAUTH_HANDLE, NULL ); 440 441 if (g_slist_find(jabber_connections, ic)) { 442 imcb_remove_buddy(ic, JABBER_OAUTH_HANDLE, NULL); 443 } 465 444 return FALSE; 466 445 } 467 446 468 static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token, const char *error ); 469 470 int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ) 447 static void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, 448 const char *error); 449 450 int sasl_oauth2_get_refresh_token(struct im_connection *ic, const char *msg) 471 451 { 472 452 struct jabber_data *jd = ic->proto_data; 473 453 char *code; 474 454 int ret; 475 476 imcb_log( ic, "Requesting OAuth access token");477 455 456 imcb_log(ic, "Requesting OAuth access token"); 457 478 458 /* Don't do it here because the caller may get confused if the contact 479 459 we're currently sending a message to is deleted. */ 480 b_timeout_add( 1, sasl_oauth2_remove_contact, ic);481 482 code = g_strdup( msg);483 g_strstrip( code);484 ret = oauth2_access_token( 485 code, sasl_oauth2_got_token, ic);486 487 g_free( code);460 b_timeout_add(1, sasl_oauth2_remove_contact, ic); 461 462 code = g_strdup(msg); 463 g_strstrip(code); 464 ret = oauth2_access_token(jd->oauth2_service, OAUTH2_AUTH_CODE, 465 code, sasl_oauth2_got_token, ic); 466 467 g_free(code); 488 468 return ret; 489 469 } 490 470 491 int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token)492 { 493 struct jabber_data *jd = ic->proto_data; 494 495 return oauth2_access_token( 496 refresh_token, sasl_oauth2_got_token, ic);497 } 498 499 static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token, const char *error)471 int sasl_oauth2_refresh(struct im_connection *ic, const char *refresh_token) 472 { 473 struct jabber_data *jd = ic->proto_data; 474 475 return oauth2_access_token(jd->oauth2_service, OAUTH2_AUTH_REFRESH, 476 refresh_token, sasl_oauth2_got_token, ic); 477 } 478 479 static void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, const char *error) 500 480 { 501 481 struct im_connection *ic = data; 502 482 struct jabber_data *jd; 503 483 GSList *auth = NULL; 504 505 if ( g_slist_find( jabber_connections, ic ) == NULL )484 485 if (g_slist_find(jabber_connections, ic) == NULL) { 506 486 return; 507 487 } 488 508 489 jd = ic->proto_data; 509 510 if( access_token == NULL ) 511 { 512 imcb_error( ic, "OAuth failure (%s)", error ); 513 imc_logout( ic, TRUE ); 490 491 if (access_token == NULL) { 492 imcb_error(ic, "OAuth failure (%s)", error); 493 imc_logout(ic, TRUE); 514 494 return; 515 495 } 516 517 oauth_params_parse( &auth, ic->acc->pass ); 518 if( refresh_token ) 519 oauth_params_set( &auth, "refresh_token", refresh_token ); 520 if( access_token ) 521 oauth_params_set( &auth, "access_token", access_token ); 522 523 g_free( ic->acc->pass ); 524 ic->acc->pass = oauth_params_string( auth ); 525 oauth_params_free( &auth ); 526 527 g_free( jd->oauth2_access_token ); 528 jd->oauth2_access_token = g_strdup( access_token ); 529 530 jabber_connect( ic ); 531 } 496 497 oauth_params_parse(&auth, ic->acc->pass); 498 if (refresh_token) { 499 oauth_params_set(&auth, "refresh_token", refresh_token); 500 } 501 if (access_token) { 502 oauth_params_set(&auth, "access_token", access_token); 503 } 504 505 g_free(ic->acc->pass); 506 ic->acc->pass = oauth_params_string(auth); 507 oauth_params_free(&auth); 508 509 g_free(jd->oauth2_access_token); 510 jd->oauth2_access_token = g_strdup(access_token); 511 512 jabber_connect(ic); 513 } -
protocols/jabber/si.c
raf359b4 r5ebff60 25 25 #include "sha1.h" 26 26 27 void jabber_si_answer_request( file_transfer_t *ft);28 int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf 27 void jabber_si_answer_request(file_transfer_t *ft); 28 int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf); 29 29 30 30 /* file_transfer free() callback */ 31 void jabber_si_free_transfer( 31 void jabber_si_free_transfer(file_transfer_t *ft) 32 32 { 33 33 struct jabber_transfer *tf = ft->data; 34 34 struct jabber_data *jd = tf->ic->proto_data; 35 35 36 if ( tf->watch_in ) 37 { 38 b_event_remove( tf->watch_in ); 36 if (tf->watch_in) { 37 b_event_remove(tf->watch_in); 39 38 tf->watch_in = 0; 40 39 } 41 40 42 jd->filetransfers = g_slist_remove( jd->filetransfers, tf ); 43 44 if( tf->fd != -1 ) 45 { 46 closesocket( tf->fd ); 41 jd->filetransfers = g_slist_remove(jd->filetransfers, tf); 42 43 if (tf->fd != -1) { 44 closesocket(tf->fd); 47 45 tf->fd = -1; 48 46 } 49 47 50 if( tf->disco_timeout ) 51 b_event_remove( tf->disco_timeout ); 52 53 g_free( tf->ini_jid ); 54 g_free( tf->tgt_jid ); 55 g_free( tf->iq_id ); 56 g_free( tf->sid ); 57 g_free( tf ); 48 if (tf->disco_timeout) { 49 b_event_remove(tf->disco_timeout); 50 } 51 52 g_free(tf->ini_jid); 53 g_free(tf->tgt_jid); 54 g_free(tf->iq_id); 55 g_free(tf->sid); 56 g_free(tf); 58 57 } 59 58 60 59 /* file_transfer canceled() callback */ 61 void jabber_si_canceled( file_transfer_t *ft, char *reason)60 void jabber_si_canceled(file_transfer_t *ft, char *reason) 62 61 { 63 62 struct jabber_transfer *tf = ft->data; 64 63 struct xt_node *reply, *iqnode; 65 64 66 if ( tf->accepted )65 if (tf->accepted) { 67 66 return; 68 69 iqnode = jabber_make_packet( "iq", "error", tf->ini_jid, NULL ); 70 xt_add_attr( iqnode, "id", tf->iq_id ); 71 reply = jabber_make_error_packet( iqnode, "forbidden", "cancel", "403" ); 72 xt_free_node( iqnode ); 73 74 if( !jabber_write_packet( tf->ic, reply ) ) 75 imcb_log( tf->ic, "WARNING: Error generating reply to file transfer request" ); 76 xt_free_node( reply ); 77 78 } 79 80 int jabber_si_check_features( struct jabber_transfer *tf, GSList *features ) { 67 } 68 69 iqnode = jabber_make_packet("iq", "error", tf->ini_jid, NULL); 70 xt_add_attr(iqnode, "id", tf->iq_id); 71 reply = jabber_make_error_packet(iqnode, "forbidden", "cancel", "403"); 72 xt_free_node(iqnode); 73 74 if (!jabber_write_packet(tf->ic, reply)) { 75 imcb_log(tf->ic, "WARNING: Error generating reply to file transfer request"); 76 } 77 xt_free_node(reply); 78 79 } 80 81 int jabber_si_check_features(struct jabber_transfer *tf, GSList *features) 82 { 81 83 int foundft = FALSE, foundbt = FALSE, foundsi = FALSE; 82 84 83 while ( features ) 84 { 85 if( !strcmp( features->data, XMLNS_FILETRANSFER ) ) 85 while (features) { 86 if (!strcmp(features->data, XMLNS_FILETRANSFER)) { 86 87 foundft = TRUE; 87 if( !strcmp( features->data, XMLNS_BYTESTREAMS ) ) 88 } 89 if (!strcmp(features->data, XMLNS_BYTESTREAMS)) { 88 90 foundbt = TRUE; 89 if( !strcmp( features->data, XMLNS_SI ) ) 91 } 92 if (!strcmp(features->data, XMLNS_SI)) { 90 93 foundsi = TRUE; 94 } 91 95 92 96 features = g_slist_next(features); 93 97 } 94 98 95 if( !foundft ) 96 imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature file transfers" ); 97 else if( !foundbt ) 98 imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature byte streams (required)" ); 99 else if( !foundsi ) 100 imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature stream initiation (required)" ); 101 99 if (!foundft) { 100 imcb_file_canceled(tf->ic, tf->ft, "Buddy's client doesn't feature file transfers"); 101 } else if (!foundbt) { 102 imcb_file_canceled(tf->ic, tf->ft, "Buddy's client doesn't feature byte streams (required)"); 103 } else if (!foundsi) { 104 imcb_file_canceled(tf->ic, tf->ft, "Buddy's client doesn't feature stream initiation (required)"); 105 } 106 102 107 return foundft && foundbt && foundsi; 103 108 } 104 109 105 void jabber_si_transfer_start( struct jabber_transfer *tf ) { 106 107 if( !jabber_si_check_features( tf, tf->bud->features ) ) 110 void jabber_si_transfer_start(struct jabber_transfer *tf) 111 { 112 113 if (!jabber_si_check_features(tf, tf->bud->features)) { 108 114 return; 109 115 } 116 110 117 /* send the request to our buddy */ 111 jabber_si_send_request( tf->ic, tf->bud->full_jid, tf);118 jabber_si_send_request(tf->ic, tf->bud->full_jid, tf); 112 119 113 120 /* and start the receive logic */ 114 imcb_file_recv_start( tf->ic, tf->ft);115 116 } 117 118 gboolean jabber_si_waitfor_disco( gpointer data, gint fd, b_input_condition cond)121 imcb_file_recv_start(tf->ic, tf->ft); 122 123 } 124 125 gboolean jabber_si_waitfor_disco(gpointer data, gint fd, b_input_condition cond) 119 126 { 120 127 struct jabber_transfer *tf = data; … … 123 130 tf->disco_timeout_fired++; 124 131 125 if ( tf->bud->features && jd->have_streamhosts==1) {132 if (tf->bud->features && jd->have_streamhosts == 1) { 126 133 tf->disco_timeout = 0; 127 jabber_si_transfer_start( tf);134 jabber_si_transfer_start(tf); 128 135 return FALSE; 129 136 } 130 137 131 138 /* 8 seconds should be enough for server and buddy to respond */ 132 if ( tf->disco_timeout_fired < 16 )139 if (tf->disco_timeout_fired < 16) { 133 140 return TRUE; 134 135 if( !tf->bud->features && jd->have_streamhosts!=1 ) 136 imcb_log( tf->ic, "Couldn't get buddy's features nor discover all services of the server" ); 137 else if( !tf->bud->features ) 138 imcb_log( tf->ic, "Couldn't get buddy's features" ); 139 else 140 imcb_log( tf->ic, "Couldn't discover some of the server's services" ); 141 141 } 142 143 if (!tf->bud->features && jd->have_streamhosts != 1) { 144 imcb_log(tf->ic, "Couldn't get buddy's features nor discover all services of the server"); 145 } else if (!tf->bud->features) { 146 imcb_log(tf->ic, "Couldn't get buddy's features"); 147 } else { 148 imcb_log(tf->ic, "Couldn't discover some of the server's services"); 149 } 150 142 151 tf->disco_timeout = 0; 143 jabber_si_transfer_start( tf);152 jabber_si_transfer_start(tf); 144 153 return FALSE; 145 154 } 146 155 147 void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who )156 void jabber_si_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *who) 148 157 { 149 158 struct jabber_transfer *tf; … … 152 161 char *server = jd->server, *s; 153 162 154 if ( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) )155 bud = jabber_buddy_by_ext_jid( ic, who, 0);156 else157 bud = jabber_buddy_by_jid( ic, who, 0);158 159 if( bud == NULL ) 160 {161 imcb_file_canceled( ic, ft, "Couldn't find buddy (BUG?)");163 if ((s = strchr(who, '=')) && jabber_chat_by_jid(ic, s + 1)) { 164 bud = jabber_buddy_by_ext_jid(ic, who, 0); 165 } else { 166 bud = jabber_buddy_by_jid(ic, who, 0); 167 } 168 169 if (bud == NULL) { 170 imcb_file_canceled(ic, ft, "Couldn't find buddy (BUG?)"); 162 171 return; 163 172 } 164 165 imcb_log( ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who);166 167 tf = g_new0( struct jabber_transfer, 1);173 174 imcb_log(ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who); 175 176 tf = g_new0(struct jabber_transfer, 1); 168 177 169 178 tf->ic = ic; … … 175 184 ft->write = jabber_bs_send_write; 176 185 177 jd->filetransfers = g_slist_prepend( jd->filetransfers, tf);186 jd->filetransfers = g_slist_prepend(jd->filetransfers, tf); 178 187 179 188 /* query buddy's features and server's streaming proxies if neccessary */ 180 189 181 if( !tf->bud->features ) 182 jabber_iq_query_features( ic, bud->full_jid ); 190 if (!tf->bud->features) { 191 jabber_iq_query_features(ic, bud->full_jid); 192 } 183 193 184 194 /* If <auto> is not set don't check for proxies */ 185 if ( ( jd->have_streamhosts!=1 ) && ( jd->streamhosts==NULL) &&186 ( strstr( set_getstr( &ic->acc->set, "proxy" ), "<auto>" ) != NULL )) {195 if ((jd->have_streamhosts != 1) && (jd->streamhosts == NULL) && 196 (strstr(set_getstr(&ic->acc->set, "proxy"), "<auto>") != NULL)) { 187 197 jd->have_streamhosts = 0; 188 jabber_iq_query_server( ic, server, XMLNS_DISCO_ITEMS);189 } else if ( jd->streamhosts!=NULL )198 jabber_iq_query_server(ic, server, XMLNS_DISCO_ITEMS); 199 } else if (jd->streamhosts != NULL) { 190 200 jd->have_streamhosts = 1; 191 192 /* if we had to do a query, wait for the result. 201 } 202 203 /* if we had to do a query, wait for the result. 193 204 * Otherwise fire away. */ 194 if( !tf->bud->features || jd->have_streamhosts!=1 ) 195 tf->disco_timeout = b_timeout_add( 500, jabber_si_waitfor_disco, tf ); 196 else 197 jabber_si_transfer_start( tf ); 205 if (!tf->bud->features || jd->have_streamhosts != 1) { 206 tf->disco_timeout = b_timeout_add(500, jabber_si_waitfor_disco, tf); 207 } else { 208 jabber_si_transfer_start(tf); 209 } 198 210 } 199 211 … … 205 217 * Then we wait for imcb to call the accept or cancel callbacks. 206 218 */ 207 int jabber_si_handle_request( 219 int jabber_si_handle_request(struct im_connection *ic, struct xt_node *node, struct xt_node *sinode) 208 220 { 209 221 struct xt_node *c, *d, *reply; … … 216 228 struct jabber_data *jd = ic->proto_data; 217 229 file_transfer_t *ft; 218 230 219 231 /* All this means we expect something like this: ( I think ) 220 232 * <iq from=... to=... id=...> 221 * 222 * 223 * 224 * 225 * 233 * <si id=id xmlns=si profile=ft> 234 * <file xmlns=ft/> 235 * <feature xmlns=feature> 236 * <x xmlns=xdata type=submit> 237 * <field var=stream-method> 226 238 * 227 239 */ 228 if( !( ini_jid = xt_find_attr( node, "from" ) ) || 229 !( tgt_jid = xt_find_attr( node, "to" ) ) || 230 !( iq_id = xt_find_attr( node, "id" ) ) || 231 !( sid = xt_find_attr( sinode, "id" ) ) || 232 !( cmp = xt_find_attr( sinode, "profile" ) ) || 233 !( 0 == strcmp( cmp, XMLNS_FILETRANSFER ) ) || 234 !( d = xt_find_node( sinode->children, "file" ) ) || 235 !( cmp = xt_find_attr( d, "xmlns" ) ) || 236 !( 0 == strcmp( cmp, XMLNS_FILETRANSFER ) ) || 237 !( name = xt_find_attr( d, "name" ) ) || 238 !( size_s = xt_find_attr( d, "size" ) ) || 239 !( 1 == sscanf( size_s, "%zd", &size ) ) || 240 !( d = xt_find_node( sinode->children, "feature" ) ) || 241 !( cmp = xt_find_attr( d, "xmlns" ) ) || 242 !( 0 == strcmp( cmp, XMLNS_FEATURE ) ) || 243 !( d = xt_find_node( d->children, "x" ) ) || 244 !( cmp = xt_find_attr( d, "xmlns" ) ) || 245 !( 0 == strcmp( cmp, XMLNS_XDATA ) ) || 246 !( cmp = xt_find_attr( d, "type" ) ) || 247 !( 0 == strcmp( cmp, "form" ) ) || 248 !( d = xt_find_node( d->children, "field" ) ) || 249 !( cmp = xt_find_attr( d, "var" ) ) || 250 !( 0 == strcmp( cmp, "stream-method" ) ) ) 251 { 252 imcb_log( ic, "WARNING: Received incomplete Stream Initiation request" ); 253 } 254 else 255 { 240 if (!(ini_jid = xt_find_attr(node, "from")) || 241 !(tgt_jid = xt_find_attr(node, "to")) || 242 !(iq_id = xt_find_attr(node, "id")) || 243 !(sid = xt_find_attr(sinode, "id")) || 244 !(cmp = xt_find_attr(sinode, "profile")) || 245 !(0 == strcmp(cmp, XMLNS_FILETRANSFER)) || 246 !(d = xt_find_node(sinode->children, "file")) || 247 !(cmp = xt_find_attr(d, "xmlns")) || 248 !(0 == strcmp(cmp, XMLNS_FILETRANSFER)) || 249 !(name = xt_find_attr(d, "name")) || 250 !(size_s = xt_find_attr(d, "size")) || 251 !(1 == sscanf(size_s, "%zd", &size)) || 252 !(d = xt_find_node(sinode->children, "feature")) || 253 !(cmp = xt_find_attr(d, "xmlns")) || 254 !(0 == strcmp(cmp, XMLNS_FEATURE)) || 255 !(d = xt_find_node(d->children, "x")) || 256 !(cmp = xt_find_attr(d, "xmlns")) || 257 !(0 == strcmp(cmp, XMLNS_XDATA)) || 258 !(cmp = xt_find_attr(d, "type")) || 259 !(0 == strcmp(cmp, "form")) || 260 !(d = xt_find_node(d->children, "field")) || 261 !(cmp = xt_find_attr(d, "var")) || 262 !(0 == strcmp(cmp, "stream-method"))) { 263 imcb_log(ic, "WARNING: Received incomplete Stream Initiation request"); 264 } else { 256 265 /* Check if we support one of the options */ 257 266 258 267 c = d->children; 259 while( ( c = xt_find_node( c, "option" ) ) ) 260 if( ( d = xt_find_node( c->children, "value" ) ) && 261 ( d->text != NULL ) && 262 ( strcmp( d->text, XMLNS_BYTESTREAMS ) == 0 ) ) 263 { 268 while ((c = xt_find_node(c, "option"))) { 269 if ((d = xt_find_node(c->children, "value")) && 270 (d->text != NULL) && 271 (strcmp(d->text, XMLNS_BYTESTREAMS) == 0)) { 264 272 requestok = TRUE; 265 273 break; 266 } 267 else 268 { 274 } else { 269 275 c = c->next; 270 276 } 271 272 if ( !requestok ) 273 imcb_log( ic, "WARNING: Unsupported file transfer request from %s", ini_jid); 274 } 275 276 if( requestok ) 277 { 277 } 278 279 if (!requestok) { 280 imcb_log(ic, "WARNING: Unsupported file transfer request from %s", ini_jid); 281 } 282 } 283 284 if (requestok) { 278 285 /* Figure out who the transfer should come frome... */ 279 286 280 287 ext_jid = ini_jid; 281 if( ( s = strchr( ini_jid, '/' ) ) ) 282 { 283 if( ( bud = jabber_buddy_by_jid( ic, ini_jid, GET_BUDDY_EXACT ) ) ) 284 { 285 bud->last_msg = time( NULL ); 288 if ((s = strchr(ini_jid, '/'))) { 289 if ((bud = jabber_buddy_by_jid(ic, ini_jid, GET_BUDDY_EXACT))) { 290 bud->last_msg = time(NULL); 286 291 ext_jid = bud->ext_jid ? : bud->bare_jid; 292 } else { 293 *s = 0; /* We need to generate a bare JID now. */ 287 294 } 288 else 289 *s = 0; /* We need to generate a bare JID now. */ 290 } 291 292 if( !( ft = imcb_file_send_start( ic, ext_jid, name, size ) ) ) 293 { 294 imcb_log( ic, "WARNING: Error handling transfer request from %s", ini_jid); 295 } 296 297 if (!(ft = imcb_file_send_start(ic, ext_jid, name, size))) { 298 imcb_log(ic, "WARNING: Error handling transfer request from %s", ini_jid); 295 299 requestok = FALSE; 296 300 } 297 301 298 if ( s )302 if (s) { 299 303 *s = '/'; 300 } 301 302 if( !requestok ) 303 { 304 reply = jabber_make_error_packet( node, "item-not-found", "cancel", NULL ); 305 if (!jabber_write_packet( ic, reply )) 306 imcb_log( ic, "WARNING: Error generating reply to file transfer request" ); 307 xt_free_node( reply ); 304 } 305 } 306 307 if (!requestok) { 308 reply = jabber_make_error_packet(node, "item-not-found", "cancel", NULL); 309 if (!jabber_write_packet(ic, reply)) { 310 imcb_log(ic, "WARNING: Error generating reply to file transfer request"); 311 } 312 xt_free_node(reply); 308 313 return XT_HANDLED; 309 314 } … … 311 316 /* Request is fine. */ 312 317 313 tf = g_new0( struct jabber_transfer, 1);314 315 tf->ini_jid = g_strdup( ini_jid);316 tf->tgt_jid = g_strdup( tgt_jid);317 tf->iq_id = g_strdup( iq_id);318 tf->sid = g_strdup( sid);318 tf = g_new0(struct jabber_transfer, 1); 319 320 tf->ini_jid = g_strdup(ini_jid); 321 tf->tgt_jid = g_strdup(tgt_jid); 322 tf->iq_id = g_strdup(iq_id); 323 tf->sid = g_strdup(sid); 319 324 tf->ic = ic; 320 325 tf->ft = ft; … … 325 330 tf->ft->canceled = jabber_si_canceled; 326 331 327 jd->filetransfers = g_slist_prepend( jd->filetransfers, tf);332 jd->filetransfers = g_slist_prepend(jd->filetransfers, tf); 328 333 329 334 return XT_HANDLED; … … 336 341 * (currently that can only be a SOCKS5 bytestream) 337 342 */ 338 void jabber_si_answer_request( file_transfer_t *ft ) { 343 void jabber_si_answer_request(file_transfer_t *ft) 344 { 339 345 struct jabber_transfer *tf = ft->data; 340 346 struct xt_node *node, *sinode, *reply; 341 347 342 348 /* generate response, start with the SI tag */ 343 sinode = xt_new_node( "si", NULL, NULL);344 xt_add_attr( sinode, "xmlns", XMLNS_SI);345 xt_add_attr( sinode, "profile", XMLNS_FILETRANSFER);346 xt_add_attr( sinode, "id", tf->sid);349 sinode = xt_new_node("si", NULL, NULL); 350 xt_add_attr(sinode, "xmlns", XMLNS_SI); 351 xt_add_attr(sinode, "profile", XMLNS_FILETRANSFER); 352 xt_add_attr(sinode, "id", tf->sid); 347 353 348 354 /* now the file tag */ 349 node = xt_new_node( "file", NULL, NULL);350 xt_add_attr( node, "xmlns", XMLNS_FILETRANSFER);351 352 xt_add_child( sinode, node);355 node = xt_new_node("file", NULL, NULL); 356 xt_add_attr(node, "xmlns", XMLNS_FILETRANSFER); 357 358 xt_add_child(sinode, node); 353 359 354 360 /* and finally the feature tag */ 355 node = xt_new_node( "field", NULL, NULL);356 xt_add_attr( node, "var", "stream-method");357 xt_add_attr( node, "type", "list-single");361 node = xt_new_node("field", NULL, NULL); 362 xt_add_attr(node, "var", "stream-method"); 363 xt_add_attr(node, "type", "list-single"); 358 364 359 365 /* Currently all we can do. One could also implement in-band (IBB) */ 360 xt_add_child( node, xt_new_node( "value", XMLNS_BYTESTREAMS, NULL ));361 362 node = xt_new_node( "x", NULL, node);363 xt_add_attr( node, "xmlns", XMLNS_XDATA);364 xt_add_attr( node, "type", "submit");365 366 node = xt_new_node( "feature", NULL, node);367 xt_add_attr( node, "xmlns", XMLNS_FEATURE);368 369 xt_add_child( sinode, node);370 371 reply = jabber_make_packet( "iq", "result", tf->ini_jid, sinode);372 xt_add_attr( reply, "id", tf->iq_id);373 374 if ( !jabber_write_packet( tf->ic, reply ) )375 imcb_log( tf->ic, "WARNING: Error generating reply to file transfer request");376 else366 xt_add_child(node, xt_new_node("value", XMLNS_BYTESTREAMS, NULL)); 367 368 node = xt_new_node("x", NULL, node); 369 xt_add_attr(node, "xmlns", XMLNS_XDATA); 370 xt_add_attr(node, "type", "submit"); 371 372 node = xt_new_node("feature", NULL, node); 373 xt_add_attr(node, "xmlns", XMLNS_FEATURE); 374 375 xt_add_child(sinode, node); 376 377 reply = jabber_make_packet("iq", "result", tf->ini_jid, sinode); 378 xt_add_attr(reply, "id", tf->iq_id); 379 380 if (!jabber_write_packet(tf->ic, reply)) { 381 imcb_log(tf->ic, "WARNING: Error generating reply to file transfer request"); 382 } else { 377 383 tf->accepted = TRUE; 378 xt_free_node( reply ); 379 } 380 381 static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) 384 } 385 xt_free_node(reply); 386 } 387 388 static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 382 389 { 383 390 struct xt_node *c, *d; 384 391 char *ini_jid = NULL, *tgt_jid, *iq_id, *cmp; 385 392 GSList *tflist; 386 struct jabber_transfer *tf =NULL;393 struct jabber_transfer *tf = NULL; 387 394 struct jabber_data *jd = ic->proto_data; 388 395 389 if( !( tgt_jid = xt_find_attr( node, "from" ) ) || 390 !( ini_jid = xt_find_attr( node, "to" ) ) ) 391 { 392 imcb_log( ic, "Invalid SI response from=%s to=%s", tgt_jid, ini_jid ); 396 if (!(tgt_jid = xt_find_attr(node, "from")) || 397 !(ini_jid = xt_find_attr(node, "to"))) { 398 imcb_log(ic, "Invalid SI response from=%s to=%s", tgt_jid, ini_jid); 393 399 return XT_HANDLED; 394 400 } 395 401 396 402 /* All this means we expect something like this: ( I think ) 397 403 * <iq from=... to=... id=...> 398 * 399 * 400 * 401 * 402 * 403 * 404 * <si xmlns=si> 405 * [ <file xmlns=ft/> ] <-- not neccessary 406 * <feature xmlns=feature> 407 * <x xmlns=xdata type=submit> 408 * <field var=stream-method> 409 * <value> 404 410 */ 405 if( !( tgt_jid = xt_find_attr( node, "from" ) ) || 406 !( ini_jid = xt_find_attr( node, "to" ) ) || 407 !( iq_id = xt_find_attr( node, "id" ) ) || 408 !( c = xt_find_node( node->children, "si" ) ) || 409 !( cmp = xt_find_attr( c, "xmlns" ) ) || 410 !( strcmp( cmp, XMLNS_SI ) == 0 ) || 411 !( d = xt_find_node( c->children, "feature" ) ) || 412 !( cmp = xt_find_attr( d, "xmlns" ) ) || 413 !( strcmp( cmp, XMLNS_FEATURE ) == 0 ) || 414 !( d = xt_find_node( d->children, "x" ) ) || 415 !( cmp = xt_find_attr( d, "xmlns" ) ) || 416 !( strcmp( cmp, XMLNS_XDATA ) == 0 ) || 417 !( cmp = xt_find_attr( d, "type" ) ) || 418 !( strcmp( cmp, "submit" ) == 0 ) || 419 !( d = xt_find_node( d->children, "field" ) ) || 420 !( cmp = xt_find_attr( d, "var" ) ) || 421 !( strcmp( cmp, "stream-method" ) == 0 ) || 422 !( d = xt_find_node( d->children, "value" ) ) ) 423 { 424 imcb_log( ic, "WARNING: Received incomplete Stream Initiation response" ); 411 if (!(tgt_jid = xt_find_attr(node, "from")) || 412 !(ini_jid = xt_find_attr(node, "to")) || 413 !(iq_id = xt_find_attr(node, "id")) || 414 !(c = xt_find_node(node->children, "si")) || 415 !(cmp = xt_find_attr(c, "xmlns")) || 416 !(strcmp(cmp, XMLNS_SI) == 0) || 417 !(d = xt_find_node(c->children, "feature")) || 418 !(cmp = xt_find_attr(d, "xmlns")) || 419 !(strcmp(cmp, XMLNS_FEATURE) == 0) || 420 !(d = xt_find_node(d->children, "x")) || 421 !(cmp = xt_find_attr(d, "xmlns")) || 422 !(strcmp(cmp, XMLNS_XDATA) == 0) || 423 !(cmp = xt_find_attr(d, "type")) || 424 !(strcmp(cmp, "submit") == 0) || 425 !(d = xt_find_node(d->children, "field")) || 426 !(cmp = xt_find_attr(d, "var")) || 427 !(strcmp(cmp, "stream-method") == 0) || 428 !(d = xt_find_node(d->children, "value"))) { 429 imcb_log(ic, "WARNING: Received incomplete Stream Initiation response"); 425 430 return XT_HANDLED; 426 431 } 427 432 428 if ( !( strcmp( d->text, XMLNS_BYTESTREAMS ) == 0 ) ) {433 if (!(strcmp(d->text, XMLNS_BYTESTREAMS) == 0)) { 429 434 /* since we should only have advertised what we can do and the peer should 430 435 * only have chosen what we offered, this should never happen */ 431 imcb_log( ic, "WARNING: Received invalid Stream Initiation response, method %s", d->text);432 436 imcb_log(ic, "WARNING: Received invalid Stream Initiation response, method %s", d->text); 437 433 438 return XT_HANDLED; 434 439 } 435 440 436 441 /* Let's see if we can find out what this bytestream should be for... */ 437 442 438 for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) ) 439 { 443 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 440 444 struct jabber_transfer *tft = tflist->data; 441 if( ( strcmp( tft->iq_id, iq_id ) == 0 ) ) 442 { 443 tf = tft; 445 if ((strcmp(tft->iq_id, iq_id) == 0)) { 446 tf = tft; 444 447 break; 445 448 } 446 449 } 447 450 448 if (!tf) 449 { 450 imcb_log( ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid ); 451 if (!tf) { 452 imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid); 451 453 return XT_HANDLED; 452 454 } 453 455 454 tf->ini_jid = g_strdup( ini_jid);455 tf->tgt_jid = g_strdup( tgt_jid);456 457 imcb_log( ic, "File %s: %s accepted the transfer!", tf->ft->file_name, tgt_jid);458 459 jabber_bs_send_start( tf);456 tf->ini_jid = g_strdup(ini_jid); 457 tf->tgt_jid = g_strdup(tgt_jid); 458 459 imcb_log(ic, "File %s: %s accepted the transfer!", tf->ft->file_name, tgt_jid); 460 461 jabber_bs_send_start(tf); 460 462 461 463 return XT_HANDLED; 462 464 } 463 465 464 int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf 466 int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf) 465 467 { 466 468 struct xt_node *node, *sinode; … … 468 470 469 471 /* who knows how many bits the future holds :) */ 470 char filesizestr[ 1 + ( int ) ( 0.301029995663981198f * sizeof( size_t ) * 8) ];471 472 const char *methods[] = 473 { 472 char filesizestr[ 1 + ( int ) (0.301029995663981198f * sizeof(size_t) * 8) ]; 473 474 const char *methods[] = 475 { 474 476 XMLNS_BYTESTREAMS, 475 477 //XMLNS_IBB, 476 NULL 478 NULL 477 479 }; 478 480 const char **m; … … 480 482 481 483 /* Maybe we should hash this? */ 482 tf->sid = g_strdup_printf( "BitlBeeJabberSID%d", tf->ft->local_id ); 483 484 if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) ) 485 bud = jabber_buddy_by_ext_jid( ic, who, 0 ); 486 else 487 bud = jabber_buddy_by_jid( ic, who, 0 ); 484 tf->sid = g_strdup_printf("BitlBeeJabberSID%d", tf->ft->local_id); 485 486 if ((s = strchr(who, '=')) && jabber_chat_by_jid(ic, s + 1)) { 487 bud = jabber_buddy_by_ext_jid(ic, who, 0); 488 } else { 489 bud = jabber_buddy_by_jid(ic, who, 0); 490 } 488 491 489 492 /* start with the SI tag */ 490 sinode = xt_new_node( "si", NULL, NULL);491 xt_add_attr( sinode, "xmlns", XMLNS_SI);492 xt_add_attr( sinode, "profile", XMLNS_FILETRANSFER);493 xt_add_attr( sinode, "id", tf->sid);494 495 /* if( mimetype ) 496 493 sinode = xt_new_node("si", NULL, NULL); 494 xt_add_attr(sinode, "xmlns", XMLNS_SI); 495 xt_add_attr(sinode, "profile", XMLNS_FILETRANSFER); 496 xt_add_attr(sinode, "id", tf->sid); 497 498 /* if( mimetype ) 499 xt_add_attr( node, "mime-type", mimetype ); */ 497 500 498 501 /* now the file tag */ 499 502 /* if( desc ) 500 501 node = xt_new_node( "range", NULL, NULL);502 503 sprintf( filesizestr, "%zd", tf->ft->file_size);504 node = xt_new_node( "file", NULL, node);505 xt_add_attr( node, "xmlns", XMLNS_FILETRANSFER);506 xt_add_attr( node, "name", tf->ft->file_name);507 xt_add_attr( node, "size", filesizestr);503 node = xt_new_node( "desc", descr, NULL ); */ 504 node = xt_new_node("range", NULL, NULL); 505 506 sprintf(filesizestr, "%zd", tf->ft->file_size); 507 node = xt_new_node("file", NULL, node); 508 xt_add_attr(node, "xmlns", XMLNS_FILETRANSFER); 509 xt_add_attr(node, "name", tf->ft->file_name); 510 xt_add_attr(node, "size", filesizestr); 508 511 /* if (hash) 509 510 511 512 513 xt_add_child( sinode, node);512 xt_add_attr( node, "hash", hash ); 513 if (date) 514 xt_add_attr( node, "date", date ); */ 515 516 xt_add_child(sinode, node); 514 517 515 518 /* and finally the feature tag */ 516 node = xt_new_node( "field", NULL, NULL ); 517 xt_add_attr( node, "var", "stream-method" ); 518 xt_add_attr( node, "type", "list-single" ); 519 520 for ( m = methods ; *m ; m ++ ) 521 xt_add_child( node, xt_new_node( "option", NULL, xt_new_node( "value", (char *)*m, NULL ) ) ); 522 523 node = xt_new_node( "x", NULL, node ); 524 xt_add_attr( node, "xmlns", XMLNS_XDATA ); 525 xt_add_attr( node, "type", "form" ); 526 527 node = xt_new_node( "feature", NULL, node ); 528 xt_add_attr( node, "xmlns", XMLNS_FEATURE ); 529 530 xt_add_child( sinode, node ); 519 node = xt_new_node("field", NULL, NULL); 520 xt_add_attr(node, "var", "stream-method"); 521 xt_add_attr(node, "type", "list-single"); 522 523 for (m = methods; *m; m++) { 524 xt_add_child(node, xt_new_node("option", NULL, xt_new_node("value", (char *) *m, NULL))); 525 } 526 527 node = xt_new_node("x", NULL, node); 528 xt_add_attr(node, "xmlns", XMLNS_XDATA); 529 xt_add_attr(node, "type", "form"); 530 531 node = xt_new_node("feature", NULL, node); 532 xt_add_attr(node, "xmlns", XMLNS_FEATURE); 533 534 xt_add_child(sinode, node); 531 535 532 536 /* and we are there... */ 533 node = jabber_make_packet( "iq", "set", bud ? bud->full_jid : who, sinode);534 jabber_cache_add( ic, node, jabber_si_handle_response);535 tf->iq_id = g_strdup( xt_find_attr( node, "id" ));536 537 return jabber_write_packet( ic, node);538 } 537 node = jabber_make_packet("iq", "set", bud ? bud->full_jid : who, sinode); 538 jabber_cache_add(ic, node, jabber_si_handle_response); 539 tf->iq_id = g_strdup(xt_find_attr(node, "id")); 540 541 return jabber_write_packet(ic, node); 542 }
Note: See TracChangeset
for help on using the changeset viewer.