Changeset 2ff2076
- Timestamp:
- 2007-12-03T14:28:45Z (17 years ago)
- Branches:
- master
- Children:
- dce3903
- Parents:
- 2c2df7d
- Files:
-
- 1 added
- 1 deleted
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
dcc.c
r2c2df7d r2ff2076 28 28 #include <poll.h> 29 29 #include <netinet/tcp.h> 30 #include <regex.h> 30 31 31 32 /* … … 76 77 gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr ); 77 78 int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr ); 79 gboolean dccs_recv_start( file_transfer_t *ft ); 80 gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond); 81 void dccs_recv_out_of_data( file_transfer_t *ft ); 78 82 79 83 /* As defined in ft.h */ … … 104 108 } 105 109 106 /* This is where the sending magic starts... */ 107 file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size ) 108 { 109 file_transfer_t *file; 110 dcc_file_transfer_t *df; 111 struct sockaddr_storage **saddr; 112 113 if( file_size > global.conf->max_filetransfer_size ) 114 return NULL; 115 116 /* alloc stuff */ 117 file = g_new0( file_transfer_t, 1 ); 118 file->priv = df = g_new0( dcc_file_transfer_t, 1); 110 /* As defined in ft.h */ 111 gboolean imcb_file_recv_start( file_transfer_t *ft ) 112 { 113 return dccs_recv_start( ft ); 114 } 115 116 dcc_file_transfer_t *dcc_alloc_transfer( char *file_name, size_t file_size, struct im_connection *ic ) 117 { 118 file_transfer_t *file = g_new0( file_transfer_t, 1 ); 119 dcc_file_transfer_t *df = file->priv = g_new0( dcc_file_transfer_t, 1); 119 120 file->file_size = file_size; 120 121 file->file_name = g_strdup( file_name ); … … 123 124 df->ft = file; 124 125 126 return df; 127 } 128 129 /* This is where the sending magic starts... */ 130 file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size ) 131 { 132 file_transfer_t *file; 133 dcc_file_transfer_t *df; 134 struct sockaddr_storage *saddr; 135 136 if( file_size > global.conf->max_filetransfer_size ) 137 return NULL; 138 139 df = dcc_alloc_transfer( file_name, file_size, ic ); 140 file = df->ft; 141 125 142 /* listen and request */ 126 if( !dcc_listen( df, saddr ) ||127 !dccs_send_request( df, user_nick, *saddr ) )143 if( !dcc_listen( df, &saddr ) || 144 !dccs_send_request( df, user_nick, saddr ) ) 128 145 return NULL; 129 146 130 g_free( *saddr );147 g_free( saddr ); 131 148 132 149 /* watch */ … … 261 278 262 279 /* 280 * Checks poll(), same for receiving and sending 281 */ 282 gboolean dcc_poll( dcc_file_transfer_t *df, int fd, short *revents ) 283 { 284 struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT }; 285 286 ASSERTSOCKOP( poll( &pfd, 1, 0 ), "poll()" ) 287 288 if( pfd.revents & POLLERR ) 289 { 290 int sockerror; 291 socklen_t errlen = sizeof( sockerror ); 292 293 if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) ) 294 return dcc_abort( df, "getsockopt() failed, unknown socket error (weird!)" ); 295 296 return dcc_abort( df, "Socket error: %s", strerror( sockerror ) ); 297 } 298 299 if( pfd.revents & POLLHUP ) 300 return dcc_abort( df, "Remote end closed connection" ); 301 302 *revents = pfd.revents; 303 304 return TRUE; 305 } 306 307 gboolean dcc_check_maxseg( dcc_file_transfer_t *df, int fd ) 308 { 309 #ifdef DCC_SEND_AHEAD 310 /* 311 * use twice the maximum segment size as a maximum for calls to send(). 312 */ 313 if( max_packet_size == 0 ) 314 { 315 unsigned int mpslen = sizeof( max_packet_size ); 316 if( getsockopt( fd, IPPROTO_TCP, TCP_MAXSEG, &max_packet_size, &mpslen ) ) 317 return dcc_abort( df, "getsockopt() failed" ); 318 max_packet_size *= 2; 319 } 320 #endif 321 return TRUE; 322 } 323 324 /* 263 325 * After setup, the transfer itself is handled entirely by this function. 264 326 * There are basically four things to handle: connect, receive, send, and error. … … 268 330 dcc_file_transfer_t *df = data; 269 331 file_transfer_t *file = df->ft; 270 struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT };271 332 short revents; 272 333 273 if ( poll( &pfd, 1, 0 ) == -1 ) 274 { 275 imcb_log( df->ic, "poll() failed, weird!" ); 276 revents = 0; 277 }; 278 279 revents = pfd.revents; 280 281 if( revents & POLLERR ) 282 { 283 int sockerror; 284 socklen_t errlen = sizeof( sockerror ); 285 286 if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) ) 287 return dcc_abort( df, "getsockopt() failed, unknown socket error (weird!)" ); 288 289 return dcc_abort( df, "Socket error: %s", strerror( sockerror ) ); 290 } 291 292 if( revents & POLLHUP ) 293 return dcc_abort( df, "Remote end closed connection" ); 294 334 if( !dcc_poll( df, fd, &revents) ) 335 return FALSE; 336 295 337 if( ( revents & POLLIN ) && 296 338 ( file->status & FT_STATUS_LISTENING ) ) … … 305 347 closesocket( fd ); 306 348 fd = df->fd; 307 file->status = FT_STATUS_TRANSFER ING;349 file->status = FT_STATUS_TRANSFERRING; 308 350 sock_make_nonblocking( fd ); 309 351 310 #ifdef DCC_SEND_AHEAD 311 /* 312 * use twice the maximum segment size as a maximum for calls to send(). 313 */ 314 if( max_packet_size == 0 ) 315 { 316 unsigned int mpslen = sizeof( max_packet_size ); 317 if( getsockopt( fd, IPPROTO_TCP, TCP_MAXSEG, &max_packet_size, &mpslen ) ) 318 return dcc_abort( df, "getsockopt() failed" ); 319 max_packet_size *= 2; 320 } 321 #endif 352 if ( !dcc_check_maxseg( df, fd ) ) 353 return FALSE; 354 322 355 /* IM protocol callback */ 323 356 … … 453 486 } 454 487 488 gboolean dccs_recv_start( file_transfer_t *ft ) 489 { 490 dcc_file_transfer_t *df = ft->priv; 491 struct sockaddr_storage *saddr = &df->saddr; 492 int fd; 493 socklen_t sa_len = saddr->ss_family == AF_INET ? 494 sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 ); 495 496 if( !ft->write ) 497 return dcc_abort( df, "Protocol didn't register write()" ); 498 499 ASSERTSOCKOP( fd = df->fd = socket( saddr->ss_family, SOCK_STREAM, 0 ) , "Opening Socket" ); 500 501 sock_make_nonblocking( fd ); 502 503 if( ( connect( fd, (struct sockaddr *)saddr, sa_len ) == -1 ) && 504 ( errno != EINPROGRESS ) ) 505 return dcc_abort( df, "Connecting" ); 506 507 ft->status = FT_STATUS_CONNECTING; 508 509 /* watch */ 510 df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_recv_proto, df ); 511 ft->out_of_data = dccs_recv_out_of_data; 512 513 return TRUE; 514 } 515 516 gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond) 517 { 518 dcc_file_transfer_t *df = data; 519 file_transfer_t *ft = df->ft; 520 short revents; 521 522 if( !dcc_poll( df, fd, &revents ) ) 523 return FALSE; 524 525 if( ( revents & POLLOUT ) && 526 ( ft->status & FT_STATUS_CONNECTING ) ) 527 { 528 ft->status = FT_STATUS_TRANSFERRING; 529 if ( !dcc_check_maxseg( df, fd ) ) 530 return FALSE; 531 532 //df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df ); 533 534 df->watch_out = 0; 535 return FALSE; 536 } 537 538 if( revents & POLLIN ) 539 { 540 char *buffer = g_malloc( 65536 ); 541 int ret, done; 542 543 ASSERTSOCKOP( ret = recv( fd, buffer, 65536, 0 ), "Receiving" ); 544 545 if( ret == 0 ) 546 return dcc_abort( df, "Remote end closed connection" ); 547 548 buffer = g_realloc( buffer, ret ); 549 550 df->bytes_sent += ret; 551 552 done = df->bytes_sent >= ft->file_size; 553 554 if( ( ( df->bytes_sent - ft->bytes_transferred ) > DCC_PACKET_SIZE ) || 555 done ) 556 { 557 int ack, ackret; 558 ack = htonl( ft->bytes_transferred = df->bytes_sent ); 559 560 ASSERTSOCKOP( ackret = send( fd, &ack, 4, 0 ), "Sending DCC ACK" ); 561 562 if ( ackret != 4 ) 563 return dcc_abort( df, "Error sending DCC ACK, sent %d instead of 4 bytes", ret ); 564 } 565 566 if( !ft->write( df->ft, buffer, ret ) && !done ) 567 { 568 df->watch_in = 0; 569 return FALSE; 570 } 571 572 if( done ) 573 { 574 closesocket( fd ); 575 dcc_finish( ft ); 576 577 df->watch_in = 0; 578 return FALSE; 579 } 580 581 return TRUE; 582 } 583 584 return TRUE; 585 } 586 587 void dccs_recv_out_of_data( file_transfer_t *ft ) 588 { 589 dcc_file_transfer_t *df = ft->priv; 590 591 if( !df->watch_in ) 592 df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df ); 593 } 594 455 595 /* 456 596 * Incoming data. Note that the buffer MUST NOT be freed by the caller! … … 472 612 df->queued_bytes += data_size; 473 613 474 if( ( file->status & FT_STATUS_TRANSFER ING ) &&614 if( ( file->status & FT_STATUS_TRANSFERRING ) && 475 615 #ifndef DCC_SEND_AHEAD 476 616 ( file->bytes_transferred >= df->bytes_sent ) && … … 533 673 dcc_close( file ); 534 674 } 675 676 /* 677 * DCC SEND <filename> <IP> <port> <filesize> 678 * 679 * filename can be in "" or not. If it is, " can probably be escaped... 680 * IP can be an unsigned int (IPV4) or something else (IPV6) 681 * 682 */ 683 file_transfer_t *dcc_request( struct im_connection *ic, char *line ) 684 { 685 char *pattern = "SEND" 686 " (([^\"][^ ]*)|\"([^\"]|\\\")*\")" 687 " (([0-9]*)|([^ ]*))" 688 " ([0-9]*)" 689 " ([0-9]*)\001"; 690 regmatch_t pmatch[9]; 691 regex_t re; 692 file_transfer_t *ft; 693 dcc_file_transfer_t *df; 694 695 if( regcomp( &re, pattern, REG_EXTENDED ) ) 696 return NULL; 697 if( regexec( &re, line, 9, pmatch, 0 ) ) 698 return NULL; 699 700 if( ( pmatch[1].rm_so > 0 ) && 701 ( pmatch[4].rm_so > 0 ) && 702 ( pmatch[7].rm_so > 0 ) && 703 ( pmatch[8].rm_so > 0 ) ) 704 { 705 char *input = g_strdup( line ); 706 char *filename, *host, *port; 707 size_t filesize; 708 struct addrinfo hints, *rp; 709 710 /* "filename" or filename */ 711 if ( pmatch[2].rm_so > 0 ) 712 { 713 input[pmatch[2].rm_eo] = '\0'; 714 filename = input + pmatch[2].rm_so; 715 } else 716 { 717 input[pmatch[3].rm_eo] = '\0'; 718 filename = input + pmatch[3].rm_so; 719 } 720 721 input[pmatch[4].rm_eo] = '\0'; 722 723 /* number means ipv4, something else means ipv6 */ 724 if ( pmatch[5].rm_so > 0 ) 725 { 726 struct in_addr ipaddr = { htonl( atoi( input + pmatch[5].rm_so ) ) }; 727 host = inet_ntoa( ipaddr ); 728 } else 729 { 730 /* Contains non-numbers, hopefully an IPV6 address */ 731 host = input + pmatch[6].rm_so; 732 } 733 734 input[pmatch[7].rm_eo] = '\0'; 735 input[pmatch[8].rm_eo] = '\0'; 736 737 port = input + pmatch[7].rm_so; 738 filesize = atoll( input + pmatch[8].rm_so ); 739 740 memset( &hints, 0, sizeof ( struct addrinfo ) ); 741 if ( getaddrinfo( host, port, &hints, &rp ) ) 742 { 743 g_free( input ); 744 return NULL; 745 } 746 747 df = dcc_alloc_transfer( filename, filesize, ic ); 748 ft = df->ft; 749 ft->sending = TRUE; 750 memcpy( &df->saddr, rp->ai_addr, rp->ai_addrlen ); 751 752 freeaddrinfo( rp ); 753 g_free( input ); 754 755 df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, ft ); 756 757 return ft; 758 } 759 760 return NULL; 761 } 762 -
dcc.h
r2c2df7d r2ff2076 112 112 size_t bytes_sent; 113 113 114 /* imc b's handle */114 /* imc's handle */ 115 115 file_transfer_t *ft; 116 117 /* if we're receiving, this is the sender's socket address */ 118 struct sockaddr_storage saddr; 116 119 117 120 } dcc_file_transfer_t; … … 123 126 gboolean dccs_send_write( file_transfer_t *file, gpointer data, unsigned int data_size ); 124 127 128 file_transfer_t *dcc_request( struct im_connection *ic, char *line ); 125 129 #endif -
doc/user-guide/commands.xml
r2c2df7d r2ff2076 861 861 862 862 </bitlbee-command> 863 864 <bitlbee-command name="transfers"> 865 <short-description>Monitor, cancel, or reject file transfers</short-description> 866 <syntax>transfers [<cancel> id | <reject>]</syntax> 867 868 <description> 869 <para> 870 Without parameters the currently pending file transfers and their status will be listed. Available actions are <emphasis>cancel</emphasis> and <emphasis>reject</emphasis>. See <emphasis>help transfers <action></emphasis> for more information. 871 </para> 872 873 <ircexample> 874 <ircline nick="ulim">transfers</ircline> 875 </ircexample> 876 </description> 877 878 <bitlbee-command name="cancel"> 879 <short-description>Cancels the file transfer with the given id</short-description> 880 <syntax>transfers <cancel> id</syntax> 881 882 <description> 883 <para>Cancels the file transfer with the given id</para> 884 </description> 885 886 <ircexample> 887 <ircline nick="ulim">transfers cancel 1</ircline> 888 <ircline nick="root">Canceling file transfer for test</ircline> 889 </ircexample> 890 </bitlbee-command> 891 892 <bitlbee-command name="reject"> 893 <short-description>Rejects all incoming transfers</short-description> 894 <syntax>transfers <reject></syntax> 895 896 <description> 897 <para>Rejects all incoming (not already transferring) file transfers. Since you probably have only one incoming transfer at a time, no id is neccessary. Or is it?</para> 898 </description> 899 900 <ircexample> 901 <ircline nick="ulim">transfers reject</ircline> 902 </ircexample> 903 </bitlbee-command> 904 </bitlbee-command> 905 863 906 </chapter> -
irc.c
r2c2df7d r2ff2076 28 28 #include "crypting.h" 29 29 #include "ipc.h" 30 #include "dcc.h" 31 32 #include <regex.h> 33 #include <netinet/in.h> 30 34 31 35 static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond ); … … 981 985 return( 1 ); 982 986 } 987 else if( g_strncasecmp( s + 1, "DCC", 3 ) == 0 ) 988 { 989 if( u && u->ic && u->ic->acc->prpl->transfer_request ) 990 { 991 file_transfer_t *ft = dcc_request( u->ic, s + 5 ); 992 if ( ft ) 993 u->ic->acc->prpl->transfer_request( u->ic, ft, u->handle ); 994 } 995 return( 1 ); 996 } 983 997 else 984 998 { 985 irc_usermsg( irc, " Non-ACTION CTCP's aren't supported" );999 irc_usermsg( irc, "Supported CTCPs are ACTION, VERSION, PING, TYPING, DCC" ); 986 1000 return( 0 ); 987 1001 } -
protocols/ft.h
r2c2df7d r2ff2076 29 29 typedef enum { 30 30 FT_STATUS_LISTENING = 1, 31 FT_STATUS_TRANSFER ING = 2,31 FT_STATUS_TRANSFERRING = 2, 32 32 FT_STATUS_FINISHED = 4, 33 FT_STATUS_CANCELED = 8 33 FT_STATUS_CANCELED = 8, 34 FT_STATUS_CONNECTING = 16 34 35 } file_status_t; 35 36 … … 61 62 */ 62 63 typedef struct file_transfer { 64 65 /* Are we sending something? */ 66 int sending; 67 63 68 /* 64 69 * The current status of this file transfer. … … 131 136 void (*out_of_data) ( struct file_transfer *file ); 132 137 138 /* 139 * When sending files, protocols register this function to receive data. 140 */ 141 gboolean (*write) (struct file_transfer *file, char *buffer, int len ); 142 133 143 } file_transfer_t; 134 144 … … 151 161 gboolean imcb_file_write( file_transfer_t *file, gpointer data, size_t data_size ); 152 162 163 gboolean imcb_file_recv_start( file_transfer_t *ft ); 153 164 #endif -
protocols/jabber/Makefile
r2c2df7d r2ff2076 10 10 11 11 # [SH] Program variables 12 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o si.o s tream.o12 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o si.o s5bytestream.o 13 13 14 14 CFLAGS += -Wall -
protocols/jabber/iq.c
r2c2df7d r2ff2076 168 168 { 169 169 /* Bytestream Request (stage 2 of file transfer) */ 170 return jabber_bs_re quest( ic, node, c );170 return jabber_bs_recv_request( ic, node, c ); 171 171 } else 172 172 { -
protocols/jabber/jabber.c
r2c2df7d r2ff2076 502 502 ret->send_typing = jabber_send_typing; 503 503 ret->handle_cmp = g_strcasecmp; 504 ret->transfer_request = jabber_si_transfer_request; 504 505 505 506 register_protocol( ret ); -
protocols/jabber/jabber.h
r2c2df7d r2ff2076 148 148 int receiver_overflow; 149 149 int fd; 150 struct sockaddr_storage saddr; 150 151 }; 151 152 … … 201 202 202 203 /* si.c */ 203 int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode); 204 205 /* stream.c */ 206 int jabber_bs_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode); 204 int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode ); 205 void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who ); 206 void jabber_si_free_transfer( file_transfer_t *ft); 207 208 /* s5bytestream.c */ 209 int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode); 210 gboolean jabber_bs_send_start( struct jabber_transfer *tf ); 211 gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, int len ); 207 212 208 213 /* message.c */ -
protocols/jabber/jabber_util.c
r2c2df7d r2ff2076 265 265 new = g_new( char, len + 1 ); 266 266 for( i = 0; i < len; i ++ ) 267 { 268 /* don't normalize the resource */ 269 if( orig[i] == '/' ) 270 break; 267 271 new[i] = tolower( orig[i] ); 272 } 273 for( ; i < len; i ++ ) 274 new[i] = orig[i]; 268 275 269 276 new[i] = 0; -
protocols/jabber/si.c
r2c2df7d r2ff2076 26 26 27 27 void jabber_si_answer_request( file_transfer_t *ft ); 28 29 /* imcb callback */ 28 int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf ); 29 30 /* file_transfer free() callback */ 30 31 void jabber_si_free_transfer( file_transfer_t *ft) 31 32 { … … 50 51 } 51 52 52 /* imcbcallback */53 /* file_transfer finished() callback */ 53 54 void jabber_si_finished( file_transfer_t *ft ) 54 55 { … … 58 59 } 59 60 60 /* imcbcallback */61 /* file_transfer canceled() callback */ 61 62 void jabber_si_canceled( file_transfer_t *ft, char *reason ) 62 63 { … … 76 77 xt_free_node( reply ); 77 78 79 } 80 81 void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who ) 82 { 83 struct jabber_transfer *tf; 84 struct jabber_data *jd = ic->proto_data; 85 86 imcb_log( ic, "Incoming file from %s : %s %zd bytes", ic->irc->nick, ft->file_name, ft->file_size ); 87 88 tf = g_new0( struct jabber_transfer, 1 ); 89 90 tf->ic = ic; 91 tf->ft = ft; 92 tf->ft->data = tf; 93 tf->ft->free = jabber_si_free_transfer; 94 tf->ft->finished = jabber_si_finished; 95 ft->write = jabber_bs_send_write; 96 97 jd->filetransfers = g_slist_prepend( jd->filetransfers, tf ); 98 99 jabber_si_send_request( ic, who, tf ); 100 101 imcb_file_recv_start( ft ); 78 102 } 79 103 … … 136 160 break; 137 161 } 162 163 if ( !requestok ) 164 imcb_log( ic, "WARNING: Unsupported file transfer request from %s", ini_jid); 138 165 } 139 166 … … 160 187 161 188 *s = '/'; 162 } else 163 imcb_log( ic, "WARNING: Unsupported file transfer request from %s", ini_jid); 189 } 164 190 165 191 if ( !requestok ) … … 245 271 xt_free_node( reply ); 246 272 } 273 274 static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) 275 { 276 struct xt_node *c, *d; 277 char *ini_jid, *tgt_jid; 278 GSList *tflist; 279 struct jabber_transfer *tf=NULL; 280 struct jabber_data *jd = ic->proto_data; 281 char *sid; 282 283 if( !( tgt_jid = xt_find_attr( node, "from" ) ) || 284 !( ini_jid = xt_find_attr( node, "to" ) ) ) 285 { 286 imcb_log( ic, "Invalid SI response from=%s to=%s", tgt_jid, ini_jid ); 287 return XT_HANDLED; 288 } 289 290 imcb_log( ic, "GOT RESPONSE TO FILE" ); 291 /* All this means we expect something like this: ( I think ) 292 * <iq from=... to=...> 293 * <si xmlns=si> 294 * <file xmlns=ft/> 295 * <feature xmlns=feature> 296 * <x xmlns=xdata type=submit> 297 * <field var=stream-method> 298 * <value> 299 */ 300 if( !( tgt_jid = xt_find_attr( node, "from" ) ) || 301 !( ini_jid = xt_find_attr( node, "to" ) ) || 302 !( c = xt_find_node( node->children, "si" ) ) || 303 !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) || 304 !( sid = xt_find_attr( c, "id" ) )|| 305 !( d = xt_find_node( c->children, "file" ) ) || 306 !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FILETRANSFER ) == 0 ) || 307 !( d = xt_find_node( c->children, "feature" ) ) || 308 !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FEATURE ) == 0 ) || 309 !( d = xt_find_node( d->children, "x" ) ) || 310 !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_XDATA ) == 0 ) || 311 !( strcmp( xt_find_attr( d, "type" ), "submit" ) == 0 ) || 312 !( d = xt_find_node( d->children, "field" ) ) || 313 !( strcmp( xt_find_attr( d, "var" ), "stream-method" ) == 0 ) || 314 !( d = xt_find_node( d->children, "value" ) ) ) 315 { 316 imcb_log( ic, "WARNING: Received incomplete Stream Initiation response" ); 317 return XT_HANDLED; 318 } 319 320 if( !( strcmp( d->text, XMLNS_BYTESTREAMS ) == 0 ) ) { 321 /* since we should only have advertised what we can do and the peer should 322 * only have chosen what we offered, this should never happen */ 323 imcb_log( ic, "WARNING: Received invalid Stream Initiation response, method %s", d->text ); 324 325 return XT_HANDLED; 326 } 327 328 /* Let's see if we can find out what this bytestream should be for... */ 329 330 for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) ) 331 { 332 struct jabber_transfer *tft = tflist->data; 333 if( ( strcmp( tft->sid, sid ) == 0 ) ) 334 { 335 tf = tft; 336 break; 337 } 338 } 339 340 if (!tf) 341 { 342 imcb_log( ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid ); 343 return XT_HANDLED; 344 } 345 346 tf->ini_jid = g_strdup( ini_jid ); 347 tf->tgt_jid = g_strdup( tgt_jid ); 348 349 jabber_bs_send_start( tf ); 350 351 return XT_HANDLED; 352 } 353 354 int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf ) 355 { 356 struct xt_node *node, *sinode; 357 struct jabber_buddy *bud; 358 359 /* who knows how many bits the future holds :) */ 360 char filesizestr[ 1 + ( int ) ( 0.301029995663981198f * sizeof( size_t ) * 8 ) ]; 361 362 const char *methods[] = 363 { 364 XMLNS_BYTESTREAMS, 365 //XMLNS_IBB, 366 NULL 367 }; 368 const char **m; 369 char *s; 370 371 /* Maybe we should hash this? */ 372 tf->sid = g_strdup_printf( "BitlBeeJabberSID%d", tf->ft->local_id ); 373 374 if( ( s = strchr( who, '=' ) ) && jabber_chat_by_name( ic, s + 1 ) ) 375 bud = jabber_buddy_by_ext_jid( ic, who, 0 ); 376 else 377 bud = jabber_buddy_by_jid( ic, who, 0 ); 378 379 /* start with the SI tag */ 380 sinode = xt_new_node( "si", NULL, NULL ); 381 xt_add_attr( sinode, "xmlns", XMLNS_SI ); 382 xt_add_attr( sinode, "profile", XMLNS_FILETRANSFER ); 383 xt_add_attr( sinode, "id", tf->sid ); 384 385 /* if( mimetype ) 386 xt_add_attr( node, "mime-type", mimetype ); */ 387 388 /* now the file tag */ 389 /* if( desc ) 390 node = xt_new_node( "desc", descr, NULL ); */ 391 node = xt_new_node( "range", NULL, NULL ); 392 393 sprintf( filesizestr, "%zd", tf->ft->file_size ); 394 node = xt_new_node( "file", NULL, node ); 395 xt_add_attr( node, "xmlns", XMLNS_FILETRANSFER ); 396 xt_add_attr( node, "name", tf->ft->file_name ); 397 xt_add_attr( node, "size", filesizestr ); 398 /* if (hash) 399 xt_add_attr( node, "hash", hash ); 400 if (date) 401 xt_add_attr( node, "date", date ); */ 402 403 xt_add_child( sinode, node ); 404 405 /* and finally the feature tag */ 406 node = xt_new_node( "field", NULL, NULL ); 407 xt_add_attr( node, "var", "stream-method" ); 408 xt_add_attr( node, "type", "list-single" ); 409 410 for ( m = methods ; *m ; m ++ ) 411 xt_add_child( node, xt_new_node( "option", NULL, xt_new_node( "value", (char *)*m, NULL ) ) ); 412 413 node = xt_new_node( "x", NULL, node ); 414 xt_add_attr( node, "xmlns", XMLNS_XDATA ); 415 xt_add_attr( node, "type", "form" ); 416 417 node = xt_new_node( "feature", NULL, node ); 418 xt_add_attr( node, "xmlns", XMLNS_FEATURE ); 419 420 xt_add_child( sinode, node ); 421 422 /* and we are there... */ 423 node = jabber_make_packet( "iq", "set", bud ? bud->full_jid : who, sinode ); 424 jabber_cache_add( ic, node, jabber_si_handle_response ); 425 426 return jabber_write_packet( ic, node ); 427 } -
protocols/nogaim.h
r2c2df7d r2ff2076 229 229 * - Most protocols will just want to set this to g_strcasecmp().*/ 230 230 int (* handle_cmp) (const char *who1, const char *who2); 231 232 /* Incoming transfer request */ 233 void (* transfer_request) (struct im_connection *, file_transfer_t *ft, char *handle ); 231 234 }; 232 235
Note: See TracChangeset
for help on using the changeset viewer.