/* file_transfer canceled() callback */ void jabber_si_canceled(file_transfer_t *ft, char *reason) { struct jabber_transfer *tf = ft->data; struct xt_node *reply, *iqnode; if (tf->accepted) { return; } iqnode = jabber_make_packet("iq", "error", tf->ini_jid, NULL); xt_add_attr(iqnode, "id", tf->iq_id); reply = jabber_make_error_packet(iqnode, "forbidden", "cancel", "403"); xt_free_node(iqnode); if (!jabber_write_packet(tf->ic, reply)) { imcb_log(tf->ic, "WARNING: Error generating reply to file transfer request"); } xt_free_node(reply); }
xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) { struct im_connection *ic = data; struct jabber_data *jd = ic->proto_data; struct xt_node *c, *reply = NULL; char *type, *s; int st, pack = 1; type = xt_find_attr( node, "type" ); if( !type ) { imcb_error( ic, "Received IQ packet without type." ); imc_logout( ic, TRUE ); return XT_ABORT; } if( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 ) { return jabber_cache_handle_packet( ic, node ); } else if( strcmp( type, "get" ) == 0 ) { if( !( ( c = xt_find_node( node->children, "query" ) ) || ( c = xt_find_node( node->children, "ping" ) ) || ( c = xt_find_node( node->children, "time" ) ) ) || !( s = xt_find_attr( c, "xmlns" ) ) ) { /* Sigh. Who decided to suddenly invent new elements instead of just sticking with <query/>? */ return XT_HANDLED; } reply = xt_new_node( "query", NULL, NULL ); xt_add_attr( reply, "xmlns", s ); /* Of course this is a very essential query to support. ;-) */ if( strcmp( s, XMLNS_VERSION ) == 0 ) { xt_add_child( reply, xt_new_node( "name", set_getstr( &ic->acc->set, "user_agent" ), NULL ) ); xt_add_child( reply, xt_new_node( "version", BITLBEE_VERSION, NULL ) ); xt_add_child( reply, xt_new_node( "os", ARCH, NULL ) ); } else if( strcmp( s, XMLNS_TIME_OLD ) == 0 ) { time_t time_ep; char buf[1024]; buf[sizeof(buf)-1] = 0; time_ep = time( NULL ); strftime( buf, sizeof( buf ) - 1, "%Y%m%dT%H:%M:%S", gmtime( &time_ep ) ); xt_add_child( reply, xt_new_node( "utc", buf, NULL ) ); strftime( buf, sizeof( buf ) - 1, "%Z", localtime( &time_ep ) ); xt_add_child( reply, xt_new_node( "tz", buf, NULL ) ); } else if( strcmp( s, XMLNS_TIME ) == 0 ) { time_t time_ep; char buf[1024]; buf[sizeof(buf)-1] = 0; time_ep = time( NULL ); xt_free_node( reply ); reply = xt_new_node( "time", NULL, NULL ); xt_add_attr( reply, "xmlns", XMLNS_TIME ); strftime( buf, sizeof( buf ) - 1, "%Y%m%dT%H:%M:%SZ", gmtime( &time_ep ) ); xt_add_child( reply, xt_new_node( "utc", buf, NULL ) ); strftime( buf, sizeof( buf ) - 1, "%z", localtime( &time_ep ) ); if( strlen( buf ) >= 5 ) { buf[6] = '\0'; buf[5] = buf[4]; buf[4] = buf[3]; buf[3] = ':'; } xt_add_child( reply, xt_new_node( "tzo", buf, NULL ) ); } else if( strcmp( s, XMLNS_PING ) == 0 ) { xt_free_node( reply ); reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), NULL ); if( ( s = xt_find_attr( node, "id" ) ) ) xt_add_attr( reply, "id", s ); pack = 0; } else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 ) { const char *features[] = { XMLNS_DISCO_INFO, XMLNS_VERSION, XMLNS_TIME_OLD, XMLNS_TIME, XMLNS_CHATSTATES, XMLNS_MUC, XMLNS_PING, XMLNS_SI, XMLNS_BYTESTREAMS, XMLNS_FILETRANSFER, NULL }; const char **f; c = xt_new_node( "identity", NULL, NULL ); xt_add_attr( c, "category", "client" ); xt_add_attr( c, "type", "pc" ); xt_add_attr( c, "name", set_getstr( &ic->acc->set, "user_agent" ) ); xt_add_child( reply, c ); for( f = features; *f; f ++ ) { c = xt_new_node( "feature", NULL, NULL ); xt_add_attr( c, "var", *f ); xt_add_child( reply, c ); } } else { xt_free_node( reply ); reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL ); pack = 0; } } else if( strcmp( type, "set" ) == 0 ) { if( ( c = xt_find_node( node->children, "si" ) ) && ( s = xt_find_attr( c, "xmlns" ) ) && ( strcmp( s, XMLNS_SI ) == 0 ) ) { return jabber_si_handle_request( ic, node, c ); } else if( !( c = xt_find_node( node->children, "query" ) ) || !( s = xt_find_attr( c, "xmlns" ) ) ) { return XT_HANDLED; } else if( strcmp( s, XMLNS_ROSTER ) == 0 ) { /* This is a roster push. XMPP servers send this when someone was added to (or removed from) the buddy list. AFAIK they're sent even if we added this buddy in our own session. */ int bare_len = strlen( jd->me ); if( ( s = xt_find_attr( node, "from" ) ) == NULL || ( strncmp( s, jd->me, bare_len ) == 0 && ( s[bare_len] == 0 || s[bare_len] == '/' ) ) ) { jabber_parse_roster( ic, node, NULL ); /* Should we generate a reply here? Don't think it's very important... */ } else { imcb_log( ic, "Warning: %s tried to fake a roster push!", s ? s : "(unknown)" ); xt_free_node( reply ); reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL ); pack = 0; } } else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 ) { /* Bytestream Request (stage 2 of file transfer) */ return jabber_bs_recv_request( ic, node, c ); } else { xt_free_node( reply ); reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL ); pack = 0; } } /* If we recognized the xmlns and managed to generate a reply, finish and send it. */ if( reply ) { /* Normally we still have to pack it into an iq-result packet, but for errors, for example, we don't. */ if( pack ) { reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), reply ); if( ( s = xt_find_attr( node, "id" ) ) ) xt_add_attr( reply, "id", s ); } st = jabber_write_packet( ic, reply ); xt_free_node( reply ); if( !st ) return XT_ABORT; } return XT_HANDLED; }