00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: dcc.c,v 1.27 2007-09-13 22:20:57 sven Exp $";
00022 #endif
00023
00024 #include <unistd.h>
00025 #include <netinet/in.h>
00026 #include <fcntl.h>
00027
00028 #include "server.h"
00029
00030 typedef struct dcc_listen {
00031 int serv, client;
00032 int timer_id, timeout;
00033 int port;
00034 } dcc_listen_t;
00035
00036 typedef struct dcc_send {
00037 struct dcc_send *next;
00038
00039 int serv, idx, port;
00040 char *nick, *ip;
00041
00042
00043 char *fname;
00044 int fd, size;
00045
00046
00047 int timer_id;
00048
00049
00050 int bytes_sent, bytes_left;
00051 int snapshot_bytes[5];
00052 int snapshot_counter;
00053 long last_snapshot;
00054 int acks, bytes_acked;
00055 long resumed_at;
00056 long request_time, connect_time;
00057 } dcc_send_t;
00058
00059 static dcc_send_t *dcc_send_head = NULL;
00060 static dcc_send_t *dcc_recv_head = NULL;
00061
00062 static int dcc_listen_newclient(void *client_data, int idx, int newidx, const char *peer_ip, int peer_port);
00063 static int dcc_listen_delete(event_owner_t *owner, void *client_data);
00064 static int dcc_listen_timeout(void *client_data);
00065 static int dcc_chat_connect(void *client_data, int idx, const char *peer_ip, int peer_port);
00066 static int dcc_chat_eof(void *client_data, int idx, int err, const char *errmsg);
00067 static int dcc_chat_delete(void *client_data, int idx);
00068 static int dcc_send_connect(void *client_data, int idx, const char *peer_ip, int peer_port);
00069 static int dcc_send_read(void *client_data, int idx, char *data, int len);
00070 static int dcc_send_written(void *client_data, int idx, int len, int remaining);
00071 static int dcc_send_eof(void *client_data, int idx, int err, const char *errmsg);
00072 static int dcc_send_delete(void *client_data, int idx);
00073 static int dcc_send_done(dcc_send_t *send);
00074 static int dcc_recv_timeout(void *client_data);
00075 static int dcc_recv_connect(void *client_data, int idx, const char *peer_ip, int peer_port);
00076 static int dcc_recv_read(void *client_data, int idx, char *data, int len);
00077 static int dcc_recv_eof(void *client_data, int idx, int err, const char *errmsg);
00078 static int dcc_recv_delete(void *client_data, int idx);
00079 static void update_snapshot(dcc_send_t *send, int len);
00080
00081 event_owner_t server_dcclistener_owner = {
00082 "server", 0,
00083 0, 0,
00084 dcc_listen_delete
00085 };
00086
00087 static sockbuf_handler_t dcc_listen_handler = {
00088 "DCC listen",
00089 NULL, NULL, dcc_listen_newclient,
00090 NULL, NULL
00091 };
00092
00093 #define DCC_FILTER_LEVEL (SOCKBUF_LEVEL_TEXT_BUFFER + 100)
00094
00095 static sockbuf_filter_t dcc_chat_filter = {
00096 "DCC chat", DCC_FILTER_LEVEL,
00097 dcc_chat_connect, dcc_chat_eof, NULL,
00098 NULL, NULL, NULL,
00099 NULL, dcc_chat_delete
00100 };
00101
00102 static sockbuf_filter_t dcc_send_filter = {
00103 "DCC send", DCC_FILTER_LEVEL,
00104 dcc_send_connect, dcc_send_eof, NULL,
00105 dcc_send_read, NULL, dcc_send_written,
00106 NULL, dcc_send_delete
00107 };
00108
00109 static sockbuf_filter_t dcc_recv_filter = {
00110 "DCC get", DCC_FILTER_LEVEL,
00111 dcc_recv_connect, dcc_recv_eof, NULL,
00112 dcc_recv_read, NULL, NULL,
00113 NULL, dcc_recv_delete
00114 };
00115
00116 static int dcc_dns_callback(void *client_data, const char *host, char **ips)
00117 {
00118 if (ips && ips[0]) str_redup(¤t_server.myip, ips[0]);
00119 else str_redup(¤t_server.myip, "127.0.0.1");
00120 socket_ip_to_uint(current_server.myip, ¤t_server.mylongip);
00121 return(0);
00122 }
00123
00124 int dcc_dns_set(const char *host)
00125 {
00126 egg_dns_lookup(host, 0, dcc_dns_callback, NULL, &server_owner);
00127 return(0);
00128 }
00129
00130 static dcc_listen_t *dcc_listen(int timeout)
00131 {
00132 dcc_listen_t *listen;
00133 int idx, port;
00134 egg_timeval_t howlong;
00135
00136 idx = egg_listen(0, &port);
00137 if (idx < 0) return(NULL);
00138
00139 listen = calloc(1, sizeof(*listen));
00140 listen->serv = idx;
00141 listen->port = port;
00142
00143 sockbuf_set_handler(idx, &dcc_listen_handler, listen, &server_dcclistener_owner);
00144
00145
00146 if (!timeout) timeout = server_config.dcc_timeout;
00147
00148 if (timeout > 0) {
00149 char buf[128];
00150
00151 snprintf(buf, sizeof(buf), "dcc listen port %d", port);
00152 howlong.sec = timeout;
00153 howlong.usec = 0;
00154 listen->timer_id = timer_create_complex(&howlong, buf, dcc_listen_timeout, listen, 0, &server_owner);
00155 }
00156
00157 return(listen);
00158 }
00159
00160
00161
00162
00163
00164
00165 int dcc_start_chat(const char *nick, int timeout)
00166 {
00167 dcc_listen_t *listen;
00168 int idx;
00169
00170
00171 listen = dcc_listen(timeout);
00172 if (!listen) return(-1);
00173
00174
00175
00176 idx = sockbuf_new();
00177 sockbuf_attach_filter(idx, &dcc_chat_filter, (void *)listen->serv);
00178 listen->client = idx;
00179
00180 printserv(SERVER_NORMAL, "PRIVMSG %s :%cDCC CHAT chat %u %d%c", nick, 1, current_server.mylongip, listen->port, 1);
00181 return(idx);
00182 }
00183
00184 static int dcc_listen_newclient(void *client_data, int idx, int newidx, const char *peer_ip, int peer_port)
00185 {
00186 int sock;
00187 dcc_listen_t *chat = client_data;
00188
00189 sock = sockbuf_get_sock(newidx);
00190 sockbuf_set_sock(newidx, -1, 0);
00191 sockbuf_delete(newidx);
00192
00193
00194
00195 sockbuf_set_sock(chat->client, sock, SOCKBUF_CONNECTING|SOCKBUF_CLIENT);
00196
00197
00198 chat->client = -1;
00199 sockbuf_delete(idx);
00200 return(0);
00201 }
00202
00203 static int dcc_listen_delete(event_owner_t *owner, void *client_data)
00204 {
00205 dcc_listen_t *listen = client_data;
00206
00207
00208 if (listen->timer_id != -1) {
00209 timer_destroy(listen->timer_id);
00210 listen->timer_id = -1;
00211 }
00212
00213
00214
00215 if (sockbuf_isvalid(listen->client)) {
00216 if (listen->timeout) {
00217 sockbuf_on_eof(listen->client, SOCKBUF_LEVEL_INTERNAL, -1, "DCC timed out");
00218 }
00219 else {
00220 sockbuf_on_eof(listen->client, SOCKBUF_LEVEL_INTERNAL, -2, "DCC listening socket unexpectedly closed");
00221 }
00222 }
00223 free(listen);
00224 return(0);
00225 }
00226
00227 static int dcc_listen_timeout(void *client_data)
00228 {
00229 dcc_listen_t *listen = client_data;
00230
00231 listen->timeout = 1;
00232 listen->timer_id = -1;
00233 sockbuf_delete(listen->serv);
00234 return(0);
00235 }
00236
00237 static int dcc_chat_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
00238 {
00239 sockbuf_detach_filter(idx, &dcc_chat_filter, NULL);
00240 return sockbuf_on_connect(idx, DCC_FILTER_LEVEL, peer_ip, peer_port);
00241 }
00242
00243 static int dcc_chat_eof(void *client_data, int idx, int err, const char *errmsg)
00244 {
00245 sockbuf_detach_filter(idx, &dcc_chat_filter, NULL);
00246 return sockbuf_on_eof(idx, DCC_FILTER_LEVEL, err, errmsg);
00247 }
00248
00249 static int dcc_chat_delete(void *client_data, int idx)
00250 {
00251 int serv = (int) client_data;
00252 sockbuf_delete(serv);
00253 return(0);
00254 }
00255
00256 int dcc_start_send(const char *nick, const char *fname, int timeout)
00257 {
00258 dcc_listen_t *listen;
00259 dcc_send_t *send;
00260 int idx, size, fd;
00261 char *quote, *slash;
00262
00263 fd = open(fname, O_RDONLY);
00264 if (!fd)
00265 return(-2);
00266
00267 size = lseek(fd, 0, SEEK_END);
00268 lseek(fd, 0, SEEK_SET);
00269
00270 listen = dcc_listen(timeout);
00271 if (!listen) {
00272 close(fd);
00273 return(-1);
00274 }
00275
00276
00277
00278 idx = sockbuf_new();
00279 send = calloc(1, sizeof(*send));
00280 sockbuf_attach_filter(idx, &dcc_send_filter, send);
00281
00282 listen->client = idx;
00283 send->next = dcc_send_head;
00284 dcc_send_head = send;
00285 send->serv = listen->serv;
00286 send->port = listen->port;
00287 send->fd = fd;
00288 send->idx = idx;
00289 send->size = size;
00290 send->bytes_sent = 0;
00291 send->bytes_left = size;
00292 timer_get_now_sec(&send->request_time);
00293 send->fname = strdup(fname);
00294 send->nick = strdup(nick);
00295
00296 slash = strrchr(fname, '/');
00297 if (slash)
00298 fname = slash+1;
00299
00300 if (strchr(fname, ' '))
00301 quote = "\"";
00302 else
00303 quote = "";
00304
00305 printserv(SERVER_NORMAL, "PRIVMSG %s :%cDCC SEND %s%s%s %u %d %d%c", nick, 1, quote, fname, quote,
00306 current_server.mylongip, listen->port, size, 1);
00307
00308 return(idx);
00309 }
00310
00311 static int dcc_send_bytes(dcc_send_t *send)
00312 {
00313 int n, out, total;
00314 char buf[4096];
00315
00316 total = 0;
00317 for (;;) {
00318
00319
00320 n = read(send->fd, buf, sizeof(buf));
00321 if (n <= 0) return(-1);
00322
00323
00324
00325
00326 out = sockbuf_write(send->idx, buf, n);
00327 if (out < 0) return(-2);
00328 send->bytes_sent += out;
00329 send->bytes_left -= out;
00330 update_snapshot(send, out);
00331 total += out;
00332 if (out < n) {
00333 sockbuf_on_written(send->idx, DCC_FILTER_LEVEL, total, n - out);
00334 if (sockbuf_isvalid(send->idx)) return(0);
00335 else return(-2);
00336 }
00337 }
00338 }
00339
00340 static int dcc_send_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
00341 {
00342 dcc_send_t *send = client_data;
00343 int n;
00344
00345 timer_get_now_sec(&send->connect_time);
00346 send->serv = -1;
00347 send->ip = strdup(peer_ip);
00348 sockbuf_on_connect(idx, DCC_FILTER_LEVEL, peer_ip, peer_port);
00349 if (sockbuf_isvalid(idx)) {
00350 n = dcc_send_bytes(send);
00351 if (n == -1) dcc_send_done(send);
00352 }
00353 return(0);
00354 }
00355
00356 static int dcc_send_read(void *client_data, int idx, char *data, int len)
00357 {
00358 dcc_send_t *send = client_data;
00359 int ack;
00360
00361 memcpy(&ack, data, sizeof(int));
00362 ack = ntohl(ack);
00363 send->acks++;
00364 send->bytes_acked = ack;
00365
00366 return(0);
00367 }
00368
00369 static int dcc_send_written(void *client_data, int idx, int len, int remaining)
00370 {
00371 dcc_send_t *send = client_data;
00372 int n;
00373
00374
00375 send->bytes_sent += len;
00376 send->bytes_left -= len;
00377 update_snapshot(send, len);
00378
00379
00380
00381 sockbuf_on_written(idx, DCC_FILTER_LEVEL, len, remaining);
00382
00383 if (!sockbuf_isvalid(idx))
00384 return(0);
00385
00386
00387
00388 n = dcc_send_bytes(send);
00389 if (n == -1 && send->bytes_left <= 0 && send->bytes_acked >= send->bytes_sent) {
00390 dcc_send_done(send);
00391 }
00392
00393 return(0);
00394 }
00395
00396 static int dcc_send_eof(void *client_data, int idx, int err, const char *errmsg)
00397 {
00398 sockbuf_on_eof(idx, DCC_FILTER_LEVEL, err, errmsg);
00399 sockbuf_delete(idx);
00400 return(0);
00401 }
00402
00403 static int dcc_send_delete(void *client_data, int idx)
00404 {
00405 dcc_send_t *send = client_data;
00406 dcc_send_t *prev, *ptr;
00407
00408 if (sockbuf_isvalid(send->serv)) {
00409 sockbuf_delete(send->serv);
00410 }
00411 if (send->fd != -1) close(send->fd);
00412 if (send->fname) free(send->fname);
00413 if (send->nick) free(send->nick);
00414 if (send->ip) free(send->ip);
00415 prev = NULL;
00416 for (ptr = dcc_send_head; ptr; ptr = ptr->next) {
00417 if (ptr == send) break;
00418 prev = ptr;
00419 }
00420 if (prev) prev->next = send->next;
00421 else dcc_send_head = send->next;
00422 free(send);
00423 return(0);
00424 }
00425
00426 static int dcc_send_done(dcc_send_t *send)
00427 {
00428 int idx;
00429
00430 idx = send->idx;
00431 close(send->fd);
00432 send->fd = -1;
00433 sockbuf_on_eof(idx, DCC_FILTER_LEVEL, 0, "Success");
00434
00435
00436 if (sockbuf_isvalid(idx)) sockbuf_delete(idx);
00437 return(0);
00438 }
00439
00440 int dcc_send_info(int idx, int field, void *valueptr)
00441 {
00442 dcc_send_t *send;
00443 int i, n;
00444 long now;
00445
00446 if (!valueptr)
00447 return(-1);
00448
00449 if (sockbuf_get_filter_data(idx, &dcc_send_filter, &send) < 0)
00450 if (sockbuf_get_filter_data(idx, &dcc_recv_filter, &send) < 0)
00451 return(-1);
00452
00453 timer_get_now_sec(&now);
00454 switch (field) {
00455 case DCC_SEND_SENT:
00456 *(int *)valueptr = send->bytes_sent;
00457 break;
00458 case DCC_SEND_LEFT:
00459 *(int *)valueptr = send->bytes_left;
00460 break;
00461 case DCC_SEND_CPS_TOTAL:
00462 if (!send->connect_time)
00463 n = 0;
00464 else if (send->connect_time >= now)
00465 n = send->bytes_sent;
00466 else
00467 n = (int) ((float) send->bytes_sent / ((float) now - (float) send->connect_time));
00468 *(int *)valueptr = n;
00469 break;
00470 case DCC_SEND_CPS_SNAPSHOT:
00471 update_snapshot(send, 0);
00472
00473
00474
00475
00476 n = 0;
00477 for (i = 0; i < 5; i++) {
00478 if (i != send->snapshot_counter)
00479 n += send->snapshot_bytes[i];
00480 }
00481 if (now - send->connect_time >= 5)
00482 n = (int) ((float) n / 4.0);
00483 else if (now - send->connect_time > 1)
00484 n = (int) ((float) n / (float) (now - send->connect_time - 1));
00485 else n = 0;
00486 *(int *)valueptr = n;
00487 break;
00488 case DCC_SEND_ACKS:
00489 *(int *)valueptr = send->acks;
00490 break;
00491 case DCC_SEND_BYTES_ACKED:
00492 *(int *)valueptr = send->bytes_acked;
00493 break;
00494 case DCC_SEND_REQUEST_TIME:
00495 *(int *)valueptr = send->request_time;
00496 break;
00497 case DCC_SEND_CONNECT_TIME:
00498 *(int *)valueptr = send->connect_time;
00499 break;
00500 default:
00501 return(-1);
00502 }
00503 return(0);
00504 }
00505
00506 int dcc_accept_send(char *nick, char *localfname, char *fname, int size, int resume, char *ip, int port, int timeout)
00507 {
00508 dcc_send_t *send;
00509 char *quote;
00510 egg_timeval_t howlong;
00511
00512 send = calloc(1, sizeof(*send));
00513 send->next = dcc_recv_head;
00514 dcc_recv_head = send;
00515
00516
00517 if (!timeout) timeout = server_config.dcc_timeout;
00518 if (timeout > 0) {
00519 char buf[128];
00520
00521 snprintf(buf, sizeof(buf), "dcc recv %s/%d", ip, port);
00522 howlong.sec = timeout;
00523 howlong.usec = 0;
00524 send->timer_id = timer_create_complex(&howlong, buf, dcc_recv_timeout, send, 0, &server_owner);
00525 }
00526 else send->connect_time = -1;
00527
00528 send->port = port;
00529 send->fname = strdup(localfname);
00530 send->nick = strdup(nick);
00531 send->ip = strdup(ip);
00532 send->size = size;
00533 send->bytes_sent = 0;
00534 send->bytes_left = size;
00535 timer_get_now_sec(&send->request_time);
00536
00537 if (resume < 0) {
00538 send->fd = open(localfname, O_RDWR | O_CREAT, 0640);
00539 resume = lseek(send->fd, 0, SEEK_END);
00540 close(send->fd);
00541 if (resume < 0) resume = 0;
00542 }
00543
00544 if (resume >= size) resume = 0;
00545
00546 if (resume) {
00547 putlog(LOG_MISC, "*", "sending resume request");
00548 send->idx = sockbuf_new();
00549 send->fd = open(localfname, O_RDWR | O_CREAT, 0640);
00550 if (resume < 0) resume = lseek(send->fd, 0, SEEK_END);
00551 else resume = lseek(send->fd, resume, SEEK_SET);
00552 if (strchr(fname, ' ')) quote = "\"";
00553 else quote = "";
00554 printserv(SERVER_NORMAL, "PRIVMSG %s :%cDCC RESUME %s%s%s %d %d%c", nick, 1, quote, fname, quote, port, resume, 1);
00555 }
00556 else {
00557 send->idx = egg_connect(ip, port, -1);
00558 send->fd = open(localfname, O_RDWR | O_CREAT | O_TRUNC, 0640);
00559 }
00560
00561 sockbuf_attach_filter(send->idx, &dcc_recv_filter, send);
00562
00563 return(send->idx);
00564 }
00565
00566 static int dcc_recv_timeout(void *client_data)
00567 {
00568 dcc_send_t *send = client_data;
00569
00570 send->timer_id = -1;
00571 sockbuf_on_eof(send->idx, SOCKBUF_LEVEL_INTERNAL, -1, "DCC timed out");
00572 return(0);
00573 }
00574
00575 static int dcc_recv_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
00576 {
00577 dcc_send_t *send = client_data;
00578
00579
00580 if (send->timer_id >= 0) timer_destroy(send->timer_id);
00581 timer_get_now_sec(&send->connect_time);
00582 sockbuf_on_connect(idx, DCC_FILTER_LEVEL, peer_ip, peer_port);
00583 return(0);
00584 }
00585
00586 static int dcc_recv_read(void *client_data, int idx, char *data, int len)
00587 {
00588 dcc_send_t *send = client_data;
00589 int nlen;
00590
00591 send->bytes_sent += len;
00592 send->bytes_left -= len;
00593 update_snapshot(send, len);
00594 write(send->fd, data, len);
00595 nlen = htonl(send->bytes_sent);
00596 sockbuf_on_write(idx, DCC_FILTER_LEVEL, (char *)&nlen, 4);
00597 return sockbuf_on_read(idx, DCC_FILTER_LEVEL, data, len);
00598 }
00599
00600 static int dcc_recv_eof(void *client_data, int idx, int err, const char *errmsg)
00601 {
00602 sockbuf_on_eof(idx, DCC_FILTER_LEVEL, err, errmsg);
00603 sockbuf_delete(idx);
00604 return(0);
00605 }
00606
00607 static int dcc_recv_delete(void *client_data, int idx)
00608 {
00609 dcc_send_t *send = client_data;
00610 dcc_send_t *prev, *ptr;
00611
00612 if (send->timer_id != -1) timer_destroy(send->timer_id);
00613
00614 if (send->fd != -1) close(send->fd);
00615 if (send->fname) free(send->fname);
00616 if (send->nick) free(send->nick);
00617 if (send->ip) free(send->ip);
00618 prev = NULL;
00619 for (ptr = dcc_recv_head; ptr; ptr = ptr->next) {
00620 if (ptr == send) break;
00621 prev = ptr;
00622 }
00623 if (prev) prev->next = send->next;
00624 else dcc_recv_head = send->next;
00625 free(send);
00626 return(0);
00627 }
00628
00629 static void update_snapshot(dcc_send_t *send, int len)
00630 {
00631 int diff;
00632 int i;
00633
00634
00635 diff = timer_get_now_sec(NULL) - send->last_snapshot;
00636 timer_get_now_sec(&send->last_snapshot);
00637 if (diff > 5) diff = 5;
00638
00639
00640 for (i = 0; i < diff; i++) {
00641 send->snapshot_counter++;
00642 if (send->snapshot_counter >= 5) send->snapshot_counter = 0;
00643 send->snapshot_bytes[send->snapshot_counter] = 0;
00644 }
00645
00646
00647 send->snapshot_bytes[send->snapshot_counter] += len;
00648 }
00649
00650 static void got_chat(char *nick, char *uhost, user_t *u, char *text)
00651 {
00652 char type[256], ip[256], port[32];
00653 int nport;
00654
00655 type[0] = ip[0] = port[0] = 0;
00656 sscanf(text, "%255[^ ] %255[^ ] %31[^ ]", type, ip, port);
00657 type[255] = ip[255] = port[31] = 0;
00658
00659
00660
00661 if (!strchr(ip, '.') && !strchr(ip, ':')) {
00662 unsigned long longip;
00663 longip = strtoul(ip, NULL, 10);
00664 snprintf(ip, sizeof(ip), "%lu.%lu.%lu.%lu", (longip >> 24) & 255, (longip >> 16) & 255, (longip >> 8) & 255, (longip) & 255);
00665 }
00666
00667 nport = atoi(port);
00668
00669 bind_check(BT_dcc_chat, u ? &u->settings[0].flags : NULL, nick, nick, uhost, u, type, ip, nport);
00670 }
00671
00672 static void got_resume(char *nick, char *uhost, user_t *u, char *text)
00673 {
00674 int port, pos, n;
00675 dcc_send_t *send;
00676 char *fname, *space;
00677
00678 fname = text;
00679 space = strrchr(text, ' ');
00680 if (space && space != text) pos = atoi(space+1);
00681 else return;
00682 *space = 0;
00683 space--;
00684 space = strrchr(text, ' ');
00685 if (space && space != text) port = atoi(space+1);
00686 else return;
00687 *space = 0;
00688
00689 for (send = dcc_send_head; send; send = send->next) {
00690 if (send->port == port && !strcasecmp(send->nick, nick)) {
00691 n = lseek(send->fd, pos, SEEK_SET);
00692 send->bytes_left -= n;
00693 send->resumed_at = n;
00694 printserv(SERVER_NORMAL, "PRIVMSG %s :%cDCC ACCEPT %s %d %d%c", nick, 1, fname, port, n, 1);
00695 break;
00696 }
00697 }
00698 }
00699
00700 static void got_accept(char *nick, char *uhost, user_t *u, char *text)
00701 {
00702 int port, pos, n;
00703 dcc_send_t *send;
00704 char *fname, *space;
00705
00706 fname = text;
00707 space = strrchr(text, ' ');
00708 if (space && space != text) pos = atoi(space+1);
00709 else return;
00710 *space = 0;
00711 space--;
00712 space = strrchr(text, ' ');
00713 if (space && space != text) port = atoi(space+1);
00714 else return;
00715 *space = 0;
00716
00717 for (send = dcc_recv_head; send; send = send->next) {
00718 if (send->port == port && !strcasecmp(send->nick, nick)) {
00719 n = lseek(send->fd, pos, SEEK_SET);
00720 send->bytes_left -= n;
00721 send->resumed_at = n;
00722 egg_reconnect(send->idx, send->ip, port, -1);
00723 break;
00724 }
00725 }
00726 }
00727
00728 static void got_send(char *nick, char *uhost, user_t *u, char *text)
00729 {
00730 char *space, *fname, ip[256];
00731 int port, size, n;
00732
00733 fname = text;
00734 space = strrchr(text, ' ');
00735 if (!space || space == text) return;
00736 size = atoi(space+1);
00737 *space-- = 0;
00738 space = strrchr(text, ' ');
00739 if (!space || space == text) return;
00740 port = atoi(space+1);
00741 *space-- = 0;
00742 space = strchr(text, ' ');
00743 if (!space || space == text) return;
00744 strlcpy(ip, space + 1, sizeof ip);
00745 *space = 0;
00746
00747 if (*fname == '"') {
00748 fname++;
00749 n = strlen(fname);
00750 if (n && fname[n-1] == '"') fname[n-1] = 0;
00751 else return;
00752 }
00753
00754
00755 if (!strchr(ip, '.') && !strchr(ip, ':')) {
00756 unsigned int longip;
00757 longip = (unsigned int) atol(ip);
00758 sprintf(ip, "%d.%d.%d.%d", (longip >> 24) & 255, (longip >> 16) & 255, (longip >> 8) & 255, (longip) & 255);
00759 }
00760
00761 bind_check(BT_dcc_recv, u ? &u->settings[0].flags : NULL, nick, nick, uhost, u, fname, ip, port, size);
00762 }
00763
00764
00765 static int got_dcc(char *nick, char *uhost, user_t *u, char *dest, char *cmd, char *text)
00766 {
00767 if (!strncasecmp(text, "chat ", 5)) {
00768 got_chat(nick, uhost, u, text+5);
00769 }
00770 else if (!strncasecmp(text, "send ", 5)) {
00771 got_send(nick, uhost, u, text+5);
00772 }
00773 else if (!strncasecmp(text, "resume ", 7)) {
00774 got_resume(nick, uhost, u, text+7);
00775 }
00776 else if (!strncasecmp(text, "accept ", 7)) {
00777 got_accept(nick, uhost, u, text+7);
00778 }
00779 return(0);
00780 }
00781
00782 bind_list_t ctcp_dcc_binds[] = {
00783 {NULL, "DCC", (Function) got_dcc},
00784 {0}
00785 };