Changes in / [2c2df7d:fa30fa5]
- Files:
-
- 1 added
- 1 deleted
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
dcc.c
r2c2df7d rfa30fa5 28 28 #include <poll.h> 29 29 #include <netinet/tcp.h> 30 #include <regex.h> 30 31 31 32 /* … … 60 61 unsigned int receivedchunks=0, receiveddata=0; 61 62 62 /*63 * If using DCC SEND AHEAD this value will be set before the first transfer starts.64 * Not that in this case it degenerates to the maximum message size to send() and65 * has nothing to do with packets.66 */67 #ifdef DCC_SEND_AHEAD68 int max_packet_size = DCC_PACKET_SIZE;69 #else70 63 int max_packet_size = 0; 71 #endif72 64 73 65 static void dcc_finish( file_transfer_t *file ); … … 76 68 gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr ); 77 69 int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr ); 70 gboolean dccs_recv_start( file_transfer_t *ft ); 71 gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond); 72 gboolean dccs_recv_write_request( file_transfer_t *ft ); 78 73 79 74 /* As defined in ft.h */ … … 99 94 100 95 /* As defined in ft.h */ 101 gboolean imcb_file_write( file_transfer_t *file, gpointer data, size_t data_size ) 102 { 103 return dccs_send_write( file, data, data_size ); 104 } 105 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); 96 gboolean imcb_file_recv_start( file_transfer_t *ft ) 97 { 98 return dccs_recv_start( ft ); 99 } 100 101 dcc_file_transfer_t *dcc_alloc_transfer( char *file_name, size_t file_size, struct im_connection *ic ) 102 { 103 file_transfer_t *file = g_new0( file_transfer_t, 1 ); 104 dcc_file_transfer_t *df = file->priv = g_new0( dcc_file_transfer_t, 1); 119 105 file->file_size = file_size; 120 106 file->file_name = g_strdup( file_name ); … … 123 109 df->ft = file; 124 110 111 return df; 112 } 113 114 /* This is where the sending magic starts... */ 115 file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size ) 116 { 117 file_transfer_t *file; 118 dcc_file_transfer_t *df; 119 struct sockaddr_storage *saddr; 120 121 if( file_size > global.conf->max_filetransfer_size ) 122 return NULL; 123 124 df = dcc_alloc_transfer( file_name, file_size, ic ); 125 file = df->ft; 126 file->write = dccs_send_write; 127 file->sending = TRUE; 128 125 129 /* listen and request */ 126 if( !dcc_listen( df, saddr ) ||127 !dccs_send_request( df, user_nick, *saddr ) )130 if( !dcc_listen( df, &saddr ) || 131 !dccs_send_request( df, user_nick, saddr ) ) 128 132 return NULL; 129 133 130 g_free( *saddr );134 g_free( saddr ); 131 135 132 136 /* watch */ … … 178 182 struct sockaddr_in *saddr_ipv4 = ( struct sockaddr_in *) saddr; 179 183 180 /*181 * this is so ridiculous. We're supposed to convert the address to182 * host byte order!!! Let's exclude anyone running big endian just183 * for the fun of it...184 */185 184 sprintf( ipaddr, "%d", 186 htonl( saddr_ipv4->sin_addr.s_addr ) );185 ntohl( saddr_ipv4->sin_addr.s_addr ) ); 187 186 port = saddr_ipv4->sin_port; 188 187 } else … … 209 208 210 209 g_free( cmd ); 211 212 /* message is sortof redundant cause the users client probably informs him about that. remove? */213 imcb_log( df->ic, "Transferring file %s: Chose local address %s for DCC connection", df->ft->file_name, ipaddr );214 210 215 211 return TRUE; … … 261 257 262 258 /* 259 * Checks poll(), same for receiving and sending 260 */ 261 gboolean dcc_poll( dcc_file_transfer_t *df, int fd, short *revents ) 262 { 263 struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT }; 264 265 ASSERTSOCKOP( poll( &pfd, 1, 0 ), "poll()" ) 266 267 if( pfd.revents & POLLERR ) 268 { 269 int sockerror; 270 socklen_t errlen = sizeof( sockerror ); 271 272 if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) ) 273 return dcc_abort( df, "getsockopt() failed, unknown socket error (weird!)" ); 274 275 return dcc_abort( df, "Socket error: %s", strerror( sockerror ) ); 276 } 277 278 if( pfd.revents & POLLHUP ) 279 return dcc_abort( df, "Remote end closed connection" ); 280 281 *revents = pfd.revents; 282 283 return TRUE; 284 } 285 286 /* 287 * fills max_packet_size with twice the TCP maximum segment size 288 */ 289 gboolean dcc_check_maxseg( dcc_file_transfer_t *df, int fd ) 290 { 291 /* 292 * use twice the maximum segment size as a maximum for calls to send(). 293 */ 294 if( max_packet_size == 0 ) 295 { 296 unsigned int mpslen = sizeof( max_packet_size ); 297 if( getsockopt( fd, IPPROTO_TCP, TCP_MAXSEG, &max_packet_size, &mpslen ) ) 298 return dcc_abort( df, "getsockopt() failed" ); 299 max_packet_size *= 2; 300 } 301 return TRUE; 302 } 303 304 /* 263 305 * After setup, the transfer itself is handled entirely by this function. 264 306 * There are basically four things to handle: connect, receive, send, and error. … … 268 310 dcc_file_transfer_t *df = data; 269 311 file_transfer_t *file = df->ft; 270 struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT };271 312 short revents; 272 313 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 314 if( !dcc_poll( df, fd, &revents) ) 315 return FALSE; 316 295 317 if( ( revents & POLLIN ) && 296 318 ( file->status & FT_STATUS_LISTENING ) ) … … 305 327 closesocket( fd ); 306 328 fd = df->fd; 307 file->status = FT_STATUS_TRANSFER ING;329 file->status = FT_STATUS_TRANSFERRING; 308 330 sock_make_nonblocking( fd ); 309 331 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 332 if ( !dcc_check_maxseg( df, fd ) ) 333 return FALSE; 334 322 335 /* IM protocol callback */ 323 324 336 if( file->accept ) 325 337 file->accept( file ); 338 326 339 /* reschedule for reading on new fd */ 327 340 df->watch_in = b_input_add( fd, GAIM_INPUT_READ, dccs_send_proto, df ); … … 367 380 } 368 381 369 #ifndef DCC_SEND_AHEAD 370 /* reschedule writer if neccessary */ 371 if( file->bytes_transferred >= df->bytes_sent && 372 df->watch_out == 0 && 373 df->queued_bytes > 0 ) { 374 df->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, dcc_send_proto, df ); 382 return TRUE; 383 } 384 385 return TRUE; 386 } 387 388 gboolean dccs_recv_start( file_transfer_t *ft ) 389 { 390 dcc_file_transfer_t *df = ft->priv; 391 struct sockaddr_storage *saddr = &df->saddr; 392 int fd; 393 socklen_t sa_len = saddr->ss_family == AF_INET ? 394 sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 ); 395 396 if( !ft->write ) 397 return dcc_abort( df, "Protocol didn't register write()" ); 398 399 ASSERTSOCKOP( fd = df->fd = socket( saddr->ss_family, SOCK_STREAM, 0 ) , "Opening Socket" ); 400 401 sock_make_nonblocking( fd ); 402 403 if( ( connect( fd, (struct sockaddr *)saddr, sa_len ) == -1 ) && 404 ( errno != EINPROGRESS ) ) 405 return dcc_abort( df, "Connecting" ); 406 407 ft->status = FT_STATUS_CONNECTING; 408 409 /* watch */ 410 df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_recv_proto, df ); 411 ft->write_request = dccs_recv_write_request; 412 413 return TRUE; 414 } 415 416 gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond) 417 { 418 dcc_file_transfer_t *df = data; 419 file_transfer_t *ft = df->ft; 420 short revents; 421 422 if( !dcc_poll( df, fd, &revents ) ) 423 return FALSE; 424 425 if( ( revents & POLLOUT ) && 426 ( ft->status & FT_STATUS_CONNECTING ) ) 427 { 428 ft->status = FT_STATUS_TRANSFERRING; 429 if ( !dcc_check_maxseg( df, fd ) ) 430 return FALSE; 431 432 //df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df ); 433 434 df->watch_out = 0; 435 return FALSE; 436 } 437 438 if( revents & POLLIN ) 439 { 440 int ret, done; 441 442 ASSERTSOCKOP( ret = recv( fd, ft->buffer, sizeof( ft->buffer ), 0 ), "Receiving" ); 443 444 if( ret == 0 ) 445 return dcc_abort( df, "Remote end closed connection" ); 446 447 df->bytes_sent += ret; 448 449 done = df->bytes_sent >= ft->file_size; 450 451 if( ( ( df->bytes_sent - ft->bytes_transferred ) > DCC_PACKET_SIZE ) || 452 done ) 453 { 454 int ack, ackret; 455 ack = htonl( ft->bytes_transferred = df->bytes_sent ); 456 457 ASSERTSOCKOP( ackret = send( fd, &ack, 4, 0 ), "Sending DCC ACK" ); 458 459 if ( ackret != 4 ) 460 return dcc_abort( df, "Error sending DCC ACK, sent %d instead of 4 bytes", ackret ); 375 461 } 376 #endif 377 return TRUE; 378 } 379 380 if( revents & POLLOUT ) 381 { 382 struct dcc_buffer *dccb; 383 int ret; 384 char *msg; 385 386 if( df->queued_bytes == 0 ) 387 { 388 /* shouldn't happen */ 389 imcb_log( df->ic, "WARNING: DCC SEND: write called with empty queue" ); 390 391 df->watch_out = 0; 462 463 if( !ft->write( df->ft, ft->buffer, ret ) ) 464 return FALSE; 465 466 if( done ) 467 { 468 closesocket( fd ); 469 dcc_finish( ft ); 470 471 df->watch_in = 0; 392 472 return FALSE; 393 473 } 394 474 395 /* start where we left off */ 396 if( !( df->queued_buffers ) || 397 !( dccb = df->queued_buffers->data ) ) 398 return dcc_abort( df, "BUG in DCC SEND: queued data but no buffers" ); 399 400 msg = dccb->b + df->buffer_pos; 401 402 int msgsize = MIN( 403 #ifndef DCC_SEND_AHEAD 404 file->bytes_transferred + MAX_PACKET_SIZE - df->bytes_sent, 405 #else 406 max_packet_size, 407 #endif 408 dccb->len - df->buffer_pos ); 409 410 if ( msgsize == 0 ) 411 { 412 df->watch_out = 0; 413 return FALSE; 414 } 415 416 ASSERTSOCKOP( ret = send( fd, msg, msgsize, 0 ), "Sending data" ); 417 418 if( ret == 0 ) 419 return dcc_abort( df, "Remote end closed connection" ); 420 421 df->bytes_sent += ret; 422 df->queued_bytes -= ret; 423 df->buffer_pos += ret; 424 425 if( df->buffer_pos == dccb->len ) 426 { 427 df->buffer_pos = 0; 428 df->queued_buffers = g_slist_remove( df->queued_buffers, dccb ); 429 g_free( dccb->b ); 430 g_free( dccb ); 431 } 432 433 if( ( df->queued_bytes < DCC_QUEUE_THRESHOLD_LOW ) && file->out_of_data ) 434 file->out_of_data( file ); 435 436 if( df->queued_bytes > 0 ) 437 { 438 /* Who knows how long the event loop cycle will take, 439 * let's just try to send some more now. */ 440 #ifndef DCC_SEND_AHEAD 441 if( df->bytes_sent < ( file->bytes_transferred + max_packet_size ) ) 442 #endif 443 return dccs_send_proto( df, fd, cond ); 444 } 445 446 df->watch_out = 0; 475 df->watch_in = 0; 447 476 return FALSE; 448 477 } 449 478 450 /* Send buffer full, come back later */ 451 452 return TRUE; 479 return TRUE; 480 } 481 482 gboolean dccs_recv_write_request( file_transfer_t *ft ) 483 { 484 dcc_file_transfer_t *df = ft->priv; 485 486 if( df->watch_in ) 487 return dcc_abort( df, "BUG: write_request() called while watching" ); 488 489 df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df ); 490 491 return TRUE; 492 } 493 494 gboolean dccs_send_can_write( gpointer data, gint fd, b_input_condition cond ) 495 { 496 struct dcc_file_transfer *df = data; 497 df->watch_out = 0; 498 499 df->ft->write_request( df->ft ); 500 return FALSE; 453 501 } 454 502 455 503 /* 456 * Incoming data. Note that the buffer MUST NOT be freed by the caller! 457 * We don't copy the buffer but put it in our queue. 504 * Incoming data. 458 505 * 459 * */460 gboolean dccs_send_write( file_transfer_t *file, gpointer data, unsigned int data_size)506 */ 507 gboolean dccs_send_write( file_transfer_t *file, char *data, unsigned int data_len ) 461 508 { 462 509 dcc_file_transfer_t *df = file->priv; 463 struct dcc_buffer *dccb = g_new0( struct dcc_buffer, 1 );464 465 receivedchunks++; receiveddata += data_ size;466 467 dccb->b = data;468 dccb->len = data_size;469 470 df->queued_buffers = g_slist_append( df->queued_buffers, dccb);471 472 df->queued_bytes += data_size;473 474 if( ( file->status & FT_STATUS_TRANSFERING ) && 475 #ifndef DCC_SEND_AHEAD 476 ( file->bytes_transferred >= df->bytes_sent ) &&477 #endif 478 ( df->watch_out == 0 ) && 479 ( df->queued_bytes > 0 ) )480 { 481 df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_send_proto, df );482 }483 484 return df->queued_bytes > DCC_QUEUE_THRESHOLD_HIGH;510 int ret; 511 512 receivedchunks++; receiveddata += data_len; 513 514 if( df->watch_out ) 515 return dcc_abort( df, "BUG: write() called while watching" ); 516 517 ASSERTSOCKOP( ret = send( df->fd, data, data_len, 0 ), "Sending data" ); 518 519 if( ret == 0 ) 520 return dcc_abort( df, "Remote end closed connection" ); 521 522 /* TODO: this should really not be fatal */ 523 if( ret < data_len ) 524 return dcc_abort( df, "send() sent %d instead of %d", ret, data_len ); 525 526 df->bytes_sent += ret; 527 528 if( df->bytes_sent < df->ft->file_size ) 529 df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_send_can_write, df ); 530 531 return TRUE; 485 532 } 486 533 … … 503 550 b_event_remove( df->watch_out ); 504 551 505 if( df->queued_buffers )506 {507 struct dcc_buffer *dccb;508 GSList *gslist = df->queued_buffers;509 510 for( ; gslist ; gslist = g_slist_next( gslist ) )511 {512 dccb = gslist->data;513 g_free( dccb->b );514 g_free( dccb );515 }516 g_slist_free( df->queued_buffers );517 }518 519 552 df->ic->irc->file_transfers = g_slist_remove( df->ic->irc->file_transfers, file ); 520 553 … … 533 566 dcc_close( file ); 534 567 } 568 569 /* 570 * DCC SEND <filename> <IP> <port> <filesize> 571 * 572 * filename can be in "" or not. If it is, " can probably be escaped... 573 * IP can be an unsigned int (IPV4) or something else (IPV6) 574 * 575 */ 576 file_transfer_t *dcc_request( struct im_connection *ic, char *line ) 577 { 578 char *pattern = "SEND" 579 " (([^\"][^ ]*)|\"([^\"]|\\\")*\")" 580 " (([0-9]*)|([^ ]*))" 581 " ([0-9]*)" 582 " ([0-9]*)\001"; 583 regmatch_t pmatch[9]; 584 regex_t re; 585 file_transfer_t *ft; 586 dcc_file_transfer_t *df; 587 588 if( regcomp( &re, pattern, REG_EXTENDED ) ) 589 return NULL; 590 if( regexec( &re, line, 9, pmatch, 0 ) ) 591 return NULL; 592 593 if( ( pmatch[1].rm_so > 0 ) && 594 ( pmatch[4].rm_so > 0 ) && 595 ( pmatch[7].rm_so > 0 ) && 596 ( pmatch[8].rm_so > 0 ) ) 597 { 598 char *input = g_strdup( line ); 599 char *filename, *host, *port; 600 size_t filesize; 601 struct addrinfo hints, *rp; 602 603 /* "filename" or filename */ 604 if ( pmatch[2].rm_so > 0 ) 605 { 606 input[pmatch[2].rm_eo] = '\0'; 607 filename = input + pmatch[2].rm_so; 608 } else 609 { 610 input[pmatch[3].rm_eo] = '\0'; 611 filename = input + pmatch[3].rm_so; 612 } 613 614 input[pmatch[4].rm_eo] = '\0'; 615 616 /* number means ipv4, something else means ipv6 */ 617 if ( pmatch[5].rm_so > 0 ) 618 { 619 struct in_addr ipaddr = { htonl( atoi( input + pmatch[5].rm_so ) ) }; 620 host = inet_ntoa( ipaddr ); 621 } else 622 { 623 /* Contains non-numbers, hopefully an IPV6 address */ 624 host = input + pmatch[6].rm_so; 625 } 626 627 input[pmatch[7].rm_eo] = '\0'; 628 input[pmatch[8].rm_eo] = '\0'; 629 630 port = input + pmatch[7].rm_so; 631 filesize = atoll( input + pmatch[8].rm_so ); 632 633 memset( &hints, 0, sizeof ( struct addrinfo ) ); 634 if ( getaddrinfo( host, port, &hints, &rp ) ) 635 { 636 g_free( input ); 637 return NULL; 638 } 639 640 df = dcc_alloc_transfer( filename, filesize, ic ); 641 ft = df->ft; 642 ft->sending = TRUE; 643 memcpy( &df->saddr, rp->ai_addr, rp->ai_addrlen ); 644 645 freeaddrinfo( rp ); 646 g_free( input ); 647 648 df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, ft ); 649 650 return ft; 651 } 652 653 return NULL; 654 } 655 -
dcc.h
r2c2df7d rfa30fa5 44 44 #define _DCC_H 45 45 46 /* don't wait for acknowledgments */ 47 #define DCC_SEND_AHEAD 48 49 /* This multiplier specifies how many bytes we 50 * can go ahead within one event loop cycle. Notice that all in all, 51 * we can easily be more ahead if the event loop shoots often enough. 52 * (or the receiver processes slow enough) 53 * 54 * Setting this value too high will cause send buffer overflows. 55 */ 56 #define DCC_SEND_AHEAD_MUL 10 57 58 /* 59 * queue thresholds for the out of data and overflow conditions 60 */ 61 #define DCC_QUEUE_THRESHOLD_LOW 2048 62 #define DCC_QUEUE_THRESHOLD_HIGH 65536 63 64 /* only used in non-ahead mode */ 46 /* Send an ACK after receiving this amount of data */ 65 47 #define DCC_PACKET_SIZE 1024 66 67 /* stores buffers handed over by IM protocols */68 struct dcc_buffer {69 char *b;70 int len;71 };72 48 73 49 typedef struct dcc_file_transfer { … … 89 65 90 66 /* 91 * The total number of queued bytes. The following equality should always hold:92 *93 * queued_bytes = sum(queued_buffers.len) - buffer_pos94 */95 unsigned int queued_bytes;96 97 /*98 * A list of dcc_buffer structures.99 * These are provided by the protocols directly so that no copying is neccessary.100 */101 GSList *queued_buffers;102 103 /*104 * current position within the first buffer.105 * Is non-null if the whole buffer couldn't be sent at once.106 */107 int buffer_pos;108 109 /*110 67 * The total amount of bytes that have been sent to the irc client. 111 68 */ 112 69 size_t bytes_sent; 113 70 114 /* imc b's handle */71 /* imc's handle */ 115 72 file_transfer_t *ft; 73 74 /* if we're receiving, this is the sender's socket address */ 75 struct sockaddr_storage saddr; 116 76 117 77 } dcc_file_transfer_t; … … 121 81 void dcc_canceled( file_transfer_t *file, char *reason ); 122 82 123 gboolean dccs_send_write( file_transfer_t *file, gpointerdata, unsigned int data_size );83 gboolean dccs_send_write( file_transfer_t *file, char *data, unsigned int data_size ); 124 84 85 file_transfer_t *dcc_request( struct im_connection *ic, char *line ); 125 86 #endif -
doc/user-guide/commands.xml
r2c2df7d rfa30fa5 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 rfa30fa5 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 rfa30fa5 27 27 #define _FT_H 28 28 29 /* 30 * One buffer is needed for each transfer. The receiver stores a message 31 * in it and gives it to the sender. The sender will stall the receiver 32 * till the buffer has been sent out. 33 */ 34 #define FT_BUFFER_SIZE 2048 35 29 36 typedef enum { 30 37 FT_STATUS_LISTENING = 1, 31 FT_STATUS_TRANSFER ING = 2,38 FT_STATUS_TRANSFERRING = 2, 32 39 FT_STATUS_FINISHED = 4, 33 FT_STATUS_CANCELED = 8 40 FT_STATUS_CANCELED = 8, 41 FT_STATUS_CONNECTING = 16 34 42 } file_status_t; 35 43 … … 61 69 */ 62 70 typedef struct file_transfer { 71 72 /* Are we sending something? */ 73 int sending; 74 63 75 /* 64 76 * The current status of this file transfer. … … 126 138 127 139 /* 128 * If set, called when the transfer queue is running empty and 129 * more data can be added. 140 * called by the sending side to indicate that it is writable. 141 * The callee should check if data is available and call the 142 * function(as seen below) if that is the case. 130 143 */ 131 void (*out_of_data) ( struct file_transfer *file ); 144 gboolean (*write_request) ( struct file_transfer *file ); 145 146 /* 147 * When sending files, protocols register this function to receive data. 148 * This should only be called once after write_request is called. The caller 149 * should not read more data until write_request is called again. This technique 150 * avoids buffering. 151 */ 152 gboolean (*write) (struct file_transfer *file, char *buffer, unsigned int len ); 153 154 /* The send buffer associated with this transfer. 155 * Since receivers always wait for a write_request call one is enough. 156 */ 157 char buffer[FT_BUFFER_SIZE]; 132 158 133 159 } file_transfer_t; … … 144 170 void imcb_file_canceled( file_transfer_t *file, char *reason ); 145 171 146 /* 147 * The given buffer is queued for transfer and MUST NOT be freed by the caller. 148 * When the method returns false the caller should not invoke this method again 149 * until out_of_data has been called. 150 */ 151 gboolean imcb_file_write( file_transfer_t *file, gpointer data, size_t data_size ); 152 172 gboolean imcb_file_recv_start( file_transfer_t *ft ); 153 173 #endif -
protocols/jabber/Makefile
r2c2df7d rfa30fa5 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 rfa30fa5 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 rfa30fa5 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 rfa30fa5 146 146 147 147 size_t bytesread, byteswritten; 148 int receiver_overflow;149 148 int fd; 149 struct sockaddr_storage saddr; 150 150 }; 151 151 … … 201 201 202 202 /* 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); 203 int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode ); 204 void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who ); 205 void jabber_si_free_transfer( file_transfer_t *ft); 206 207 /* s5bytestream.c */ 208 int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode); 209 gboolean jabber_bs_send_start( struct jabber_transfer *tf ); 210 gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len ); 207 211 208 212 /* message.c */ -
protocols/jabber/jabber_util.c
r2c2df7d rfa30fa5 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 rfa30fa5 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, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who ); 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 ) … … 198 224 199 225 /* 200 * imc bcalled the accept callback which probably means that the user accepted this file transfer.226 * imc called the accept callback which probably means that the user accepted this file transfer. 201 227 * We send our response to the initiator. 202 228 * In the next step, the initiator will send us a request for the given stream type. … … 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, *iq_id; 278 GSList *tflist; 279 struct jabber_transfer *tf=NULL; 280 struct jabber_data *jd = ic->proto_data; 281 282 if( !( tgt_jid = xt_find_attr( node, "from" ) ) || 283 !( ini_jid = xt_find_attr( node, "to" ) ) ) 284 { 285 imcb_log( ic, "Invalid SI response from=%s to=%s", tgt_jid, ini_jid ); 286 return XT_HANDLED; 287 } 288 289 /* All this means we expect something like this: ( I think ) 290 * <iq from=... to=... id=...> 291 * <si xmlns=si> 292 * [ <file xmlns=ft/> ] <-- not neccessary 293 * <feature xmlns=feature> 294 * <x xmlns=xdata type=submit> 295 * <field var=stream-method> 296 * <value> 297 */ 298 if( !( tgt_jid = xt_find_attr( node, "from" ) ) || 299 !( ini_jid = xt_find_attr( node, "to" ) ) || 300 !( iq_id = xt_find_attr( node, "id" ) ) || 301 !( c = xt_find_node( node->children, "si" ) ) || 302 !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) || 303 /* !( d = xt_find_node( c->children, "file" ) ) || 304 !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FILETRANSFER ) == 0 ) || */ 305 !( d = xt_find_node( c->children, "feature" ) ) || 306 !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FEATURE ) == 0 ) || 307 !( d = xt_find_node( d->children, "x" ) ) || 308 !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_XDATA ) == 0 ) || 309 !( strcmp( xt_find_attr( d, "type" ), "submit" ) == 0 ) || 310 !( d = xt_find_node( d->children, "field" ) ) || 311 !( strcmp( xt_find_attr( d, "var" ), "stream-method" ) == 0 ) || 312 !( d = xt_find_node( d->children, "value" ) ) ) 313 { 314 imcb_log( ic, "WARNING: Received incomplete Stream Initiation response" ); 315 return XT_HANDLED; 316 } 317 318 if( !( strcmp( d->text, XMLNS_BYTESTREAMS ) == 0 ) ) { 319 /* since we should only have advertised what we can do and the peer should 320 * only have chosen what we offered, this should never happen */ 321 imcb_log( ic, "WARNING: Received invalid Stream Initiation response, method %s", d->text ); 322 323 return XT_HANDLED; 324 } 325 326 /* Let's see if we can find out what this bytestream should be for... */ 327 328 for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) ) 329 { 330 struct jabber_transfer *tft = tflist->data; 331 if( ( strcmp( tft->iq_id, iq_id ) == 0 ) ) 332 { 333 tf = tft; 334 break; 335 } 336 } 337 338 if (!tf) 339 { 340 imcb_log( ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid ); 341 return XT_HANDLED; 342 } 343 344 tf->ini_jid = g_strdup( ini_jid ); 345 tf->tgt_jid = g_strdup( tgt_jid ); 346 347 imcb_log( ic, "File %s: %s accepted the transfer!", tf->ft->file_name, 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 tf->iq_id = g_strdup( xt_find_attr( node, "id" ) ); 426 427 return jabber_write_packet( ic, node ); 428 } -
protocols/nogaim.h
r2c2df7d rfa30fa5 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.