Changeset 256899f for protocols/jabber
- Timestamp:
- 2007-11-19T23:16:18Z (17 years ago)
- Branches:
- master
- Children:
- 7df5a08
- Parents:
- cd428e4 (diff), ef5c185 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- protocols/jabber
- Files:
-
- 1 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/jabber/Makefile
rcd428e4 r256899f 10 10 11 11 # [SH] Program variables 12 objects = io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o12 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o 13 13 14 14 CFLAGS += -Wall -
protocols/jabber/io.c
rcd428e4 r256899f 44 44 struct jabber_data *jd = ic->proto_data; 45 45 gboolean ret; 46 47 if( jd->flags & JFLAG_XMLCONSOLE ) 48 { 49 char *msg; 50 51 msg = g_strdup_printf( "TX: %s", buf ); 52 imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 ); 53 g_free( msg ); 54 } 46 55 47 56 if( jd->tx_len == 0 ) … … 427 436 { 428 437 struct im_connection *ic = data; 429 struct xt_node *c;430 char *s, *type = NULL, *text = NULL;431 438 int allow_reconnect = TRUE; 432 433 for( c = node->children; c; c = c->next ) 434 { 435 if( !( s = xt_find_attr( c, "xmlns" ) ) || 436 strcmp( s, XMLNS_STREAM_ERROR ) != 0 ) 437 continue; 438 439 if( strcmp( c->name, "text" ) != 0 ) 440 { 441 type = c->name; 442 } 443 /* Only use the text if it doesn't have an xml:lang attribute, 444 if it's empty or if it's set to something English. */ 445 else if( !( s = xt_find_attr( c, "xml:lang" ) ) || 446 !*s || strncmp( s, "en", 2 ) == 0 ) 447 { 448 text = c->text; 449 } 450 } 439 struct jabber_error *err; 440 441 err = jabber_error_parse( node, XMLNS_STREAM_ERROR ); 451 442 452 443 /* Tssk... */ 453 if( type == NULL )444 if( err->code == NULL ) 454 445 { 455 446 imcb_error( ic, "Unknown stream error reported by server" ); 456 447 imc_logout( ic, allow_reconnect ); 448 jabber_error_free( err ); 457 449 return XT_ABORT; 458 450 } … … 461 453 should turn off auto-reconnect to make sure we won't get some nasty 462 454 infinite loop! */ 463 if( strcmp( type, "conflict" ) == 0 )455 if( strcmp( err->code, "conflict" ) == 0 ) 464 456 { 465 457 imcb_error( ic, "Account and resource used from a different location" ); … … 468 460 else 469 461 { 470 imcb_error( ic, "Stream error: %s%s%s", type, text ? ": " : "", text ? text : "" ); 471 } 472 462 imcb_error( ic, "Stream error: %s%s%s", err->code, err->text ? ": " : "", 463 err->text ? err->text : "" ); 464 } 465 466 jabber_error_free( err ); 473 467 imc_logout( ic, allow_reconnect ); 474 468 … … 476 470 } 477 471 472 static xt_status jabber_xmlconsole( struct xt_node *node, gpointer data ) 473 { 474 struct im_connection *ic = data; 475 struct jabber_data *jd = ic->proto_data; 476 477 if( jd->flags & JFLAG_XMLCONSOLE ) 478 { 479 char *msg, *pkt; 480 481 pkt = xt_to_string( node ); 482 msg = g_strdup_printf( "RX: %s", pkt ); 483 imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 ); 484 g_free( msg ); 485 g_free( pkt ); 486 } 487 488 return XT_NEXT; 489 } 490 478 491 static const struct xt_handler_entry jabber_handlers[] = { 492 { NULL, "stream:stream", jabber_xmlconsole }, 479 493 { "stream:stream", "<root>", jabber_end_of_stream }, 480 494 { "message", "stream:stream", jabber_pkt_message }, -
protocols/jabber/iq.c
rcd428e4 r256899f 99 99 else if( strcmp( s, XMLNS_DISCOVER ) == 0 ) 100 100 { 101 const char *features[] = { XMLNS_VERSION, 102 XMLNS_TIME, 103 XMLNS_CHATSTATES, 104 XMLNS_MUC, 105 NULL }; 106 const char **f; 107 101 108 c = xt_new_node( "identity", NULL, NULL ); 102 109 xt_add_attr( c, "category", "client" ); … … 105 112 xt_add_child( reply, c ); 106 113 107 c = xt_new_node( "feature", NULL, NULL ); 108 xt_add_attr( c, "var", XMLNS_VERSION ); 109 xt_add_child( reply, c ); 110 111 c = xt_new_node( "feature", NULL, NULL ); 112 xt_add_attr( c, "var", XMLNS_TIME ); 113 xt_add_child( reply, c ); 114 115 c = xt_new_node( "feature", NULL, NULL ); 116 xt_add_attr( c, "var", XMLNS_CHATSTATES ); 117 xt_add_child( reply, c ); 118 119 /* Later this can be useful to announce things like 120 MUC support. */ 114 for( f = features; *f; f ++ ) 115 { 116 c = xt_new_node( "feature", NULL, NULL ); 117 xt_add_attr( c, "var", *f ); 118 xt_add_child( reply, c ); 119 } 121 120 } 122 121 else … … 373 372 group->text : NULL ); 374 373 375 imcb_rename_buddy( ic, jid, name ); 374 if( name ) 375 imcb_rename_buddy( ic, jid, name ); 376 376 } 377 377 else if( strcmp( sub, "remove" ) == 0 ) 378 378 { 379 /* Don't have any API call for this yet! So let's380 just try to handle this as well as we can. */381 379 jabber_buddy_remove_bare( ic, jid ); 382 imcb_buddy_status( ic, jid, 0, NULL, NULL ); 383 /* FIXME! */ 380 imcb_remove_buddy( ic, jid, NULL ); 384 381 } 385 382 } -
protocols/jabber/jabber.c
rcd428e4 r256899f 54 54 55 55 s = set_add( &acc->set, "tls", "try", set_eval_tls, acc ); 56 s->flags |= ACC_SET_OFFLINE_ONLY; 57 58 s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc ); 56 59 s->flags |= ACC_SET_OFFLINE_ONLY; 57 60 } … … 189 192 imc_logout( ic, TRUE ); 190 193 } 194 195 if( set_getbool( &acc->set, "xmlconsole" ) ) 196 { 197 jd->flags |= JFLAG_XMLCONSOLE; 198 /* Shouldn't really do this at this stage already, maybe. But 199 I think this shouldn't break anything. */ 200 imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); 201 } 191 202 } 192 203 … … 196 207 197 208 jabber_end_stream( ic ); 209 210 while( ic->groupchats ) 211 jabber_chat_free( ic->groupchats ); 198 212 199 213 if( jd->r_inpa >= 0 ) … … 224 238 struct jabber_buddy *bud; 225 239 struct xt_node *node; 240 char *s; 226 241 int st; 227 242 228 bud = jabber_buddy_by_jid( ic, who, 0 ); 243 if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) 244 return jabber_write( ic, message, strlen( message ) ); 245 246 if( ( s = strchr( who, '=' ) ) && jabber_chat_by_name( ic, s + 1 ) ) 247 bud = jabber_buddy_by_ext_jid( ic, who, 0 ); 248 else 249 bud = jabber_buddy_by_jid( ic, who, 0 ); 229 250 230 251 node = xt_new_node( "body", message, NULL ); … … 311 332 static void jabber_add_buddy( struct im_connection *ic, char *who, char *group ) 312 333 { 334 struct jabber_data *jd = ic->proto_data; 335 336 if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) 337 { 338 jd->flags |= JFLAG_XMLCONSOLE; 339 imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); 340 return; 341 } 342 313 343 if( jabber_add_to_roster( ic, who, NULL ) ) 314 344 presence_send_request( ic, who, "subscribe" ); … … 317 347 static void jabber_remove_buddy( struct im_connection *ic, char *who, char *group ) 318 348 { 349 struct jabber_data *jd = ic->proto_data; 350 351 if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) 352 { 353 jd->flags &= ~JFLAG_XMLCONSOLE; 354 /* Not necessary for now. And for now the code isn't too 355 happy if the buddy is completely gone right after calling 356 this function already. 357 imcb_remove_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); 358 */ 359 return; 360 } 361 319 362 /* We should always do this part. Clean up our administration a little bit. */ 320 363 jabber_buddy_remove_bare( ic, who ); … … 322 365 if( jabber_remove_from_roster( ic, who ) ) 323 366 presence_send_request( ic, who, "unsubscribe" ); 367 } 368 369 static struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room, char *nick, char *password ) 370 { 371 if( strchr( room, '@' ) == NULL ) 372 imcb_error( ic, "Invalid room name: %s", room ); 373 else if( jabber_chat_by_name( ic, room ) ) 374 imcb_error( ic, "Already present in chat `%s'", room ); 375 else 376 return jabber_chat_join( ic, room, nick, password ); 377 378 return NULL; 379 } 380 381 static void jabber_chat_msg_( struct groupchat *c, char *message, int flags ) 382 { 383 if( c && message ) 384 jabber_chat_msg( c, message, flags ); 385 } 386 387 static void jabber_chat_topic_( struct groupchat *c, char *topic ) 388 { 389 if( c && topic ) 390 jabber_chat_topic( c, topic ); 391 } 392 393 static void jabber_chat_leave_( struct groupchat *c ) 394 { 395 if( c ) 396 jabber_chat_leave( c, NULL ); 324 397 } 325 398 … … 388 461 ret->buddy_msg = jabber_buddy_msg; 389 462 ret->away_states = jabber_away_states; 390 // ret->get_status_string = jabber_get_status_string;391 463 ret->set_away = jabber_set_away; 392 464 // ret->set_info = jabber_set_info; … … 394 466 ret->add_buddy = jabber_add_buddy; 395 467 ret->remove_buddy = jabber_remove_buddy; 396 // ret->chat_msg = jabber_chat_msg; 468 ret->chat_msg = jabber_chat_msg_; 469 ret->chat_topic = jabber_chat_topic_; 397 470 // ret->chat_invite = jabber_chat_invite; 398 // ret->chat_leave = jabber_chat_leave;399 // ret->chat_open = jabber_chat_open;471 ret->chat_leave = jabber_chat_leave_; 472 ret->chat_join = jabber_chat_join_; 400 473 ret->keepalive = jabber_keepalive; 401 474 ret->send_typing = jabber_send_typing; -
protocols/jabber/jabber.h
rcd428e4 r256899f 32 32 typedef enum 33 33 { 34 JFLAG_STREAM_STARTED = 1, 34 JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream 35 35 and want to do auth. */ 36 JFLAG_AUTHENTICATED = 2, 37 JFLAG_STREAM_RESTART = 4, 36 JFLAG_AUTHENTICATED = 2, /* Set when we're successfully authenticatd. */ 37 JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after 38 38 SASL or TLS). */ 39 JFLAG_WAIT_SESSION = 8, 39 JFLAG_WAIT_SESSION = 8, /* Set if we sent a <session> tag and need a reply 40 40 before we continue. */ 41 JFLAG_WAIT_BIND = 16, 42 JFLAG_WANT_TYPING = 32, 41 JFLAG_WAIT_BIND = 16, /* ... for <bind> tag. */ 42 JFLAG_WANT_TYPING = 32, /* Set if we ever sent a typing notification, this 43 43 activates all XEP-85 related code. */ 44 JFLAG_XMLCONSOLE = 64, /* If the user added an xmlconsole buddy. */ 44 45 } jabber_flags_t; 45 46 … … 50 51 JBFLAG_DOES_XEP85 = 2, /* Set this when the resource seems to support 51 52 XEP85 (typing notification shite). */ 53 JBFLAG_IS_CHATROOM = 4, /* It's convenient to use this JID thingy for 54 groupchat state info too. */ 55 JBFLAG_IS_ANONYMOUS = 8, /* For anonymous chatrooms, when we don't have 56 have a real JID. */ 52 57 } jabber_buddy_flags_t; 53 54 #define JABBER_PORT_DEFAULT "5222"55 #define JABBER_PORT_MIN 522056 #define JABBER_PORT_MAX 522957 58 58 59 struct jabber_data … … 101 102 char *resource; 102 103 104 char *ext_jid; /* The JID to use in BitlBee. The real JID if possible, */ 105 /* otherwise something similar to the conference JID. */ 106 103 107 int priority; 104 108 struct jabber_away_state *away_state; … … 110 114 struct jabber_buddy *next; 111 115 }; 116 117 struct jabber_chat 118 { 119 int flags; 120 char *name; 121 char *my_full_jid; /* Separate copy because of case sensitivity. */ 122 struct jabber_buddy *me; 123 }; 124 125 #define JABBER_XMLCONSOLE_HANDLE "xmlconsole" 126 127 #define JABBER_PORT_DEFAULT "5222" 128 #define JABBER_PORT_MIN 5220 129 #define JABBER_PORT_MAX 5229 112 130 113 131 /* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the … … 132 150 #define XMLNS_TIME "jabber:iq:time" /* XEP-0090 */ 133 151 #define XMLNS_VCARD "vcard-temp" /* XEP-0054 */ 152 #define XMLNS_DELAY "jabber:x:delay" /* XEP-0091 */ 134 153 #define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" /* 0085 */ 135 154 #define XMLNS_DISCOVER "http://jabber.org/protocol/disco#info" /* 0030 */ 155 #define XMLNS_MUC "http://jabber.org/protocol/muc" /* XEP-0045 */ 156 #define XMLNS_MUC_USER "http://jabber.org/protocol/muc#user"/* XEP-0045 */ 136 157 137 158 /* iq.c */ … … 164 185 const struct jabber_away_state *jabber_away_state_by_name( char *name ); 165 186 void jabber_buddy_ask( struct im_connection *ic, char *handle ); 166 char *jabber_normalize( c har *orig );187 char *jabber_normalize( const char *orig ); 167 188 168 189 typedef enum 169 190 { 170 191 GET_BUDDY_CREAT = 1, /* Try to create it, if necessary. */ 171 GET_BUDDY_EXACT = 2, /* Get an exact message (only makes sense with bare JIDs). */ 192 GET_BUDDY_EXACT = 2, /* Get an exact match (only makes sense with bare JIDs). */ 193 GET_BUDDY_FIRST = 4, /* No selection, simply get the first resource for this JID. */ 172 194 } get_buddy_flags_t; 195 196 struct jabber_error 197 { 198 char *code, *text, *type; 199 }; 173 200 174 201 struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid ); 175 202 struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); 203 struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); 176 204 int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); 177 205 int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); 206 struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name ); 207 time_t jabber_get_timestamp( struct xt_node *xt ); 208 struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ); 209 void jabber_error_free( struct jabber_error *err ); 178 210 179 211 extern const struct jabber_away_state jabber_away_state_list[]; … … 193 225 gboolean sasl_supported( struct im_connection *ic ); 194 226 227 /* conference.c */ 228 struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ); 229 void jabber_chat_free( struct groupchat *c ); 230 int jabber_chat_msg( struct groupchat *ic, char *message, int flags ); 231 int jabber_chat_topic( struct groupchat *c, char *topic ); 232 int jabber_chat_leave( struct groupchat *c, const char *reason ); 233 void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); 234 void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); 235 195 236 #endif -
protocols/jabber/jabber_util.c
rcd428e4 r256899f 48 48 call p_s_u() now to send the new prio setting, it would 49 49 send the old setting because the set->value gets changed 50 when theeval returns a non-NULL value.50 after the (this) eval returns a non-NULL value. 51 51 52 52 So now I can choose between implementing post-set … … 129 129 /* Cache a node/packet for later use. Mainly useful for IQ packets if you need 130 130 them when you receive the response. Use this BEFORE sending the packet so 131 it'll get a new id= tag, and do NOT free() the packet after writing it! */131 it'll get a new id= tag, and do NOT free() the packet after sending it! */ 132 132 void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func ) 133 133 { … … 252 252 253 253 /* Returns a new string. Don't leak it! */ 254 char *jabber_normalize( c har *orig )254 char *jabber_normalize( const char *orig ) 255 255 { 256 256 int len, i; … … 320 320 else 321 321 { 322 /* Keep in mind that full_jid currently isn't really 323 a full JID... */ 322 324 new->bare_jid = g_strdup( full_jid ); 323 325 g_hash_table_insert( jd->buddies, new->bare_jid, new ); … … 333 335 { 334 336 /* Let's waste some more bytes of RAM instead of to make 335 memory management a total disaster here.. */ 337 memory management a total disaster here. And it saves 338 me one g_free() call in this function. :-P */ 336 339 new->full_jid = full_jid; 337 340 } … … 353 356 if( ( s = strchr( jid, '/' ) ) ) 354 357 { 358 int none_found = 0; 359 355 360 *s = 0; 356 361 if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) … … 370 375 } 371 376 } 372 373 if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid ) ) 377 else 378 { 379 /* This hack is there to make sure that O_CREAT will 380 work if there's already another resouce present 381 for this JID, even if it's an unknown buddy. This 382 is done to handle conferences properly. */ 383 none_found = 1; 384 } 385 386 if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && ( imcb_find_buddy( ic, jid ) || !none_found ) ) 374 387 { 375 388 *s = '/'; … … 418 431 } 419 432 433 /* I'm keeping a separate ext_jid attribute to save a JID that makes sense 434 to export to BitlBee. This is mainly for groupchats right now. It's 435 a bit of a hack, but I just think having the user nickname in the hostname 436 part of the hostmask doesn't look nice on IRC. Normally you can convert 437 a normal JID to ext_jid by swapping the part before and after the / and 438 replacing the / with a =. But there should be some stripping (@s are 439 allowed in Jabber nicks...). */ 440 struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags ) 441 { 442 struct jabber_buddy *bud; 443 char *s, *jid; 444 445 jid = jabber_normalize( jid_ ); 446 447 if( ( s = strchr( jid, '=' ) ) == NULL ) 448 return NULL; 449 450 for( bud = jabber_buddy_by_jid( ic, s + 1, GET_BUDDY_FIRST ); bud; bud = bud->next ) 451 { 452 /* Hmmm, could happen if not all people in the chat are anonymized? */ 453 if( bud->ext_jid == NULL ) 454 continue; 455 456 if( strcmp( bud->ext_jid, jid ) == 0 ) 457 break; 458 } 459 460 g_free( jid ); 461 462 return bud; 463 } 464 420 465 /* Remove one specific full JID from our list. Use this when a buddy goes 421 466 off-line (because (s)he can still be online from a different location. … … 441 486 g_hash_table_remove( jd->buddies, bud->bare_jid ); 442 487 g_free( bud->bare_jid ); 488 g_free( bud->ext_jid ); 443 489 g_free( bud->full_jid ); 444 490 g_free( bud->away_message ); … … 473 519 g_hash_table_replace( jd->buddies, bi->bare_jid, bi->next ); 474 520 521 g_free( bi->ext_jid ); 475 522 g_free( bi->full_jid ); 476 523 g_free( bi->away_message ); … … 495 542 specified bare JID. Use this when removing someone from the contact 496 543 list, for example. */ 497 int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid _)544 int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ) 498 545 { 499 546 struct jabber_data *jd = ic->proto_data; 500 547 struct jabber_buddy *bud, *next; 501 char *bare_jid; 502 503 if( strchr( bare_jid_, '/' ) ) 548 549 if( strchr( bare_jid, '/' ) ) 504 550 return 0; 505 551 506 bare_jid = jabber_normalize( bare_jid_ ); 507 508 if( ( bud = g_hash_table_lookup( jd->buddies, bare_jid ) ) ) 552 if( ( bud = jabber_buddy_by_jid( ic, bare_jid, GET_BUDDY_FIRST ) ) ) 509 553 { 510 554 /* Most important: Remove the hash reference. We don't know 511 555 this buddy anymore. */ 512 556 g_hash_table_remove( jd->buddies, bud->bare_jid ); 557 g_free( bud->bare_jid ); 513 558 514 559 /* Deallocate the linked list of resources. */ 515 560 while( bud ) 516 561 { 562 /* ext_jid && anonymous means that this buddy is 563 specific to one groupchat (the one we're 564 currently cleaning up) so it can be deleted 565 completely. */ 566 if( bud->ext_jid && bud->flags & JBFLAG_IS_ANONYMOUS ) 567 imcb_remove_buddy( ic, bud->ext_jid, NULL ); 568 517 569 next = bud->next; 570 g_free( bud->ext_jid ); 518 571 g_free( bud->full_jid ); 519 572 g_free( bud->away_message ); … … 522 575 } 523 576 524 g_free( bare_jid );525 577 return 1; 526 578 } 527 579 else 528 580 { 529 g_free( bare_jid );530 581 return 0; 531 582 } 532 583 } 584 585 struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name ) 586 { 587 char *normalized = jabber_normalize( name ); 588 struct groupchat *ret; 589 struct jabber_chat *jc; 590 591 for( ret = ic->groupchats; ret; ret = ret->next ) 592 { 593 jc = ret->data; 594 if( strcmp( normalized, jc->name ) == 0 ) 595 break; 596 } 597 g_free( normalized ); 598 599 return ret; 600 } 601 602 time_t jabber_get_timestamp( struct xt_node *xt ) 603 { 604 struct tm tp, utc; 605 struct xt_node *c; 606 time_t res, tres; 607 char *s = NULL; 608 609 for( c = xt->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) 610 { 611 if( ( s = xt_find_attr( c, "xmlns" ) ) && strcmp( s, XMLNS_DELAY ) == 0 ) 612 break; 613 } 614 615 if( !c || !( s = xt_find_attr( c, "stamp" ) ) ) 616 return 0; 617 618 memset( &tp, 0, sizeof( tp ) ); 619 if( sscanf( s, "%4d%2d%2dT%2d:%2d:%2d", &tp.tm_year, &tp.tm_mon, &tp.tm_mday, 620 &tp.tm_hour, &tp.tm_min, &tp.tm_sec ) != 6 ) 621 return 0; 622 623 tp.tm_year -= 1900; 624 tp.tm_mon --; 625 tp.tm_isdst = -1; /* GRRRRRRRRRRR */ 626 627 res = mktime( &tp ); 628 /* Problem is, mktime() just gave us the GMT timestamp for the 629 given local time... While the given time WAS NOT local. So 630 we should fix this now. 631 632 Now I could choose between messing with environment variables 633 (kludgy) or using timegm() (not portable)... Or doing the 634 following, which I actually prefer... */ 635 gmtime_r( &res, &utc ); 636 utc.tm_isdst = -1; /* Once more: GRRRRRRRRRRRRRRRRRR!!! */ 637 if( utc.tm_hour == tp.tm_hour && utc.tm_min == tp.tm_min ) 638 /* Sweet! We're in UTC right now... */ 639 return res; 640 641 tres = mktime( &utc ); 642 res += res - tres; 643 644 /* Yes, this is a hack. And it will go wrong around DST changes. 645 BUT this is more likely to be threadsafe than messing with 646 environment variables, and possibly more portable... */ 647 648 return res; 649 } 650 651 struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ) 652 { 653 struct jabber_error *err = g_new0( struct jabber_error, 1 ); 654 struct xt_node *c; 655 char *s; 656 657 err->type = xt_find_attr( node, "type" ); 658 659 for( c = node->children; c; c = c->next ) 660 { 661 if( !( s = xt_find_attr( c, "xmlns" ) ) || 662 strcmp( s, xmlns ) != 0 ) 663 continue; 664 665 if( strcmp( c->name, "text" ) != 0 ) 666 { 667 err->code = c->name; 668 } 669 /* Only use the text if it doesn't have an xml:lang attribute, 670 if it's empty or if it's set to something English. */ 671 else if( !( s = xt_find_attr( c, "xml:lang" ) ) || 672 !*s || strncmp( s, "en", 2 ) == 0 ) 673 { 674 err->text = c->text; 675 } 676 } 677 678 return err; 679 } 680 681 void jabber_error_free( struct jabber_error *err ) 682 { 683 g_free( err ); 684 } -
protocols/jabber/message.c
rcd428e4 r256899f 30 30 char *type = xt_find_attr( node, "type" ); 31 31 struct xt_node *body = xt_find_node( node->children, "body" ), *c; 32 struct jabber_buddy *bud = NULL; 32 33 char *s; 34 35 if( !from ) 36 return XT_HANDLED; /* Consider this packet corrupted. */ 37 38 bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ); 33 39 34 40 if( type && strcmp( type, "error" ) == 0 ) … … 36 42 /* Handle type=error packet. */ 37 43 } 38 else if( type && strcmp( type, "groupchat" ) == 0 )44 else if( type && from && strcmp( type, "groupchat" ) == 0 ) 39 45 { 40 /* TODO! */46 jabber_chat_pkt_message( ic, bud, node ); 41 47 } 42 48 else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */ 43 49 { 44 struct jabber_buddy *bud = NULL;45 50 GString *fullmsg = g_string_new( "" ); 46 51 47 52 if( ( s = strchr( from, '/' ) ) ) 48 53 { 49 if( ( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) ) ) 54 if( bud ) 55 { 50 56 bud->last_act = time( NULL ); 57 from = bud->ext_jid ? : bud->bare_jid; 58 } 51 59 else 52 60 *s = 0; /* We need to generate a bare JID now. */ … … 76 84 77 85 if( fullmsg->len > 0 ) 78 imcb_buddy_msg( ic, bud ? bud->bare_jid : from, fullmsg->str, 0, 0 ); 86 imcb_buddy_msg( ic, from, fullmsg->str, 87 0, jabber_get_timestamp( node ) ); 79 88 80 89 g_string_free( fullmsg, TRUE ); 81 90 82 91 /* Handling of incoming typing notifications. */ 83 if( xt_find_node( node->children, "composing" ) ) 92 if( bud == NULL ) 93 { 94 /* Can't handle these for unknown buddies. */ 95 } 96 else if( xt_find_node( node->children, "composing" ) ) 84 97 { 85 98 bud->flags |= JBFLAG_DOES_XEP85; 86 imcb_buddy_typing( ic, bud ? bud->bare_jid :from, OPT_TYPING );99 imcb_buddy_typing( ic, from, OPT_TYPING ); 87 100 } 88 101 /* No need to send a "stopped typing" signal when there's a message. */ … … 90 103 { 91 104 bud->flags |= JBFLAG_DOES_XEP85; 92 imcb_buddy_typing( ic, bud ? bud->bare_jid :from, 0 );105 imcb_buddy_typing( ic, from, 0 ); 93 106 } 94 107 else if( xt_find_node( node->children, "paused" ) ) 95 108 { 96 109 bud->flags |= JBFLAG_DOES_XEP85; 97 imcb_buddy_typing( ic, bud ? bud->bare_jid :from, OPT_THINKING );110 imcb_buddy_typing( ic, from, OPT_THINKING ); 98 111 } 99 112 -
protocols/jabber/presence.c
rcd428e4 r256899f 31 31 struct xt_node *c; 32 32 struct jabber_buddy *bud; 33 int is_chat = 0, is_away = 0; 33 34 char *s; 34 35 … … 36 37 return XT_HANDLED; 37 38 39 if( ( s = strchr( from, '/' ) ) ) 40 { 41 *s = 0; 42 if( jabber_chat_by_name( ic, from ) ) 43 is_chat = 1; 44 *s = '/'; 45 } 46 38 47 if( type == NULL ) 39 48 { 40 int is_away = 0;41 42 49 if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) 43 50 { … … 72 79 bud->priority = 0; 73 80 74 if( bud == jabber_buddy_by_jid( ic, bud->bare_jid, 0 ) ) 81 if( is_chat ) 82 jabber_chat_pkt_presence( ic, bud, node ); 83 else if( bud == jabber_buddy_by_jid( ic, bud->bare_jid, 0 ) ) 75 84 imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away, 76 85 ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL, … … 79 88 else if( strcmp( type, "unavailable" ) == 0 ) 80 89 { 81 if( jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT) == NULL )90 if( ( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) ) == NULL ) 82 91 { 83 92 if( set_getbool( &ic->irc->set, "debug" ) ) … … 86 95 } 87 96 97 /* Handle this before we delete the JID. */ 98 if( is_chat ) 99 { 100 jabber_chat_pkt_presence( ic, bud, node ); 101 } 102 88 103 jabber_buddy_remove( ic, from ); 89 104 90 if( ( s = strchr( from, '/' ) ) ) 105 if( is_chat ) 106 { 107 /* Nothing else to do for now? */ 108 } 109 else if( ( s = strchr( from, '/' ) ) ) 91 110 { 92 111 *s = 0; 93 112 94 /* Only count this as offline if there's no other resource 95 available anymore. */ 96 if( jabber_buddy_by_jid( ic, from, 0 ) == NULL ) 113 /* If another resource is still available, send its presence 114 information. */ 115 if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) ) 116 { 117 if( bud->away_state && ( *bud->away_state->code == 0 || 118 strcmp( bud->away_state->code, "chat" ) == 0 ) ) 119 is_away = OPT_AWAY; 120 121 imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away, 122 ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL, 123 bud->away_message ); 124 } 125 else 126 { 127 /* Otherwise, count him/her as offline now. */ 97 128 imcb_buddy_status( ic, from, 0, NULL, NULL ); 129 } 98 130 99 131 *s = '/'; … … 126 158 else if( strcmp( type, "error" ) == 0 ) 127 159 { 128 /* What to do with it? */ 160 struct jabber_error *err; 161 162 if( ( c = xt_find_node( node->children, "error" ) ) ) 163 { 164 err = jabber_error_parse( c, XMLNS_STANZA_ERROR ); 165 imcb_error( ic, "Stanza (%s) error: %s%s%s", node->name, 166 err->code, err->text ? ": " : "", 167 err->text ? err->text : "" ); 168 jabber_error_free( err ); 169 } 170 /* What else to do with it? */ 129 171 } 130 172 … … 140 182 char *show = jd->away_state->code; 141 183 char *status = jd->away_message; 184 struct groupchat *c; 142 185 int st; 143 186 … … 151 194 st = jabber_write_packet( ic, node ); 152 195 196 /* Have to send this update to all groupchats too, the server won't 197 do this automatically. */ 198 for( c = ic->groupchats; c && st; c = c->next ) 199 { 200 struct jabber_chat *jc = c->data; 201 202 xt_add_attr( node, "to", jc->my_full_jid ); 203 st = jabber_write_packet( ic, node ); 204 } 205 153 206 xt_free_node( node ); 154 207 return st; -
protocols/jabber/sasl.c
rcd428e4 r256899f 332 332 struct jabber_data *jd = ic->proto_data; 333 333 334 return ( (void*) ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) ) != NULL;335 } 334 return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != 0; 335 } -
protocols/jabber/xmltree.c
rcd428e4 r256899f 444 444 list, not the node itself! The reason you have to do this by hand: So 445 445 that you can also use this function as a find-next. */ 446 struct xt_node *xt_find_node( struct xt_node *node, c har *name )446 struct xt_node *xt_find_node( struct xt_node *node, const char *name ) 447 447 { 448 448 while( node ) … … 457 457 } 458 458 459 char *xt_find_attr( struct xt_node *node, c har *key )459 char *xt_find_attr( struct xt_node *node, const char *key ) 460 460 { 461 461 int i; … … 526 526 } 527 527 528 void xt_add_attr( struct xt_node *node, c har *key,char *value )528 void xt_add_attr( struct xt_node *node, const char *key, const char *value ) 529 529 { 530 530 int i; … … 553 553 } 554 554 555 int xt_remove_attr( struct xt_node *node, c har *key )555 int xt_remove_attr( struct xt_node *node, const char *key ) 556 556 { 557 557 int i, last; -
protocols/jabber/xmltree.h
rcd428e4 r256899f 87 87 void xt_free_node( struct xt_node *node ); 88 88 void xt_free( struct xt_parser *xt ); 89 struct xt_node *xt_find_node( struct xt_node *node, c har *name );90 char *xt_find_attr( struct xt_node *node, c har *key );89 struct xt_node *xt_find_node( struct xt_node *node, const char *name ); 90 char *xt_find_attr( struct xt_node *node, const char *key ); 91 91 92 92 struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ); 93 93 void xt_add_child( struct xt_node *parent, struct xt_node *child ); 94 void xt_add_attr( struct xt_node *node, c har *key,char *value );95 int xt_remove_attr( struct xt_node *node, c har *key );94 void xt_add_attr( struct xt_node *node, const char *key, const char *value ); 95 int xt_remove_attr( struct xt_node *node, const char *key ); 96 96 97 97 #endif
Note: See TracChangeset
for help on using the changeset viewer.