📄 dcc.c
字号:
return TRUE; dcc_send_data (NULL, 0, (gpointer)dcc); } if (dcc->pos >= dcc->size && dcc->ack >= dcc->size) { dcc_close (dcc, STAT_DONE, FALSE); sprintf (buf, "%d", dcc->cps); EMIT_SIGNAL (XP_TE_DCCSENDCOMP, dcc->serv->front_session, file_part (dcc->file), dcc->nick, buf, NULL, 0); } return TRUE;}static gbooleandcc_accept (GIOChannel *source, GIOCondition condition, struct DCC *dcc){ char host[128]; struct sockaddr_in CAddr; int sok; size_t len; len = sizeof (CAddr); sok = accept (dcc->sok, (struct sockaddr *) &CAddr, &len); fe_input_remove (dcc->iotag); dcc->iotag = 0; closesocket (dcc->sok); if (sok < 0) { dcc->sok = -1; dcc_close (dcc, STAT_FAILED, FALSE); return TRUE; } set_nonblocking (sok); dcc->sok = sok; dcc->addr = ntohl (CAddr.sin_addr.s_addr); dcc->dccstat = STAT_ACTIVE; dcc->lasttime = dcc->starttime = time (0); dcc->fastsend = prefs.fastdccsend; switch (dcc->type) { case TYPE_SEND: if (dcc->fastsend) dcc->wiotag = fe_input_add (sok, 0, 1, 0, dcc_send_data, dcc); dcc->iotag = fe_input_add (sok, 1, 0, 1, dcc_read_ack, dcc); dcc_send_data (NULL, 0, (gpointer)dcc); break; case TYPE_CHATSEND: dcc->iotag = fe_input_add (dcc->sok, 1, 0, 1, dcc_read_chat, dcc); dcc->dccchat = malloc (sizeof (struct dcc_chat)); dcc->dccchat->pos = 0; break; } update_dcc_window (dcc->type); snprintf (host, sizeof host, "%s:%d", net_ip (dcc->addr), dcc->port); EMIT_SIGNAL (XP_TE_DCCCON, dcc->serv->front_session, dcctypes[(int) dcc->type], dcc->nick, host, "from", 0); return TRUE;}static intdcc_listen_init (struct DCC *dcc, session *sess){ size_t len; unsigned long my_addr; struct sockaddr_in SAddr; int i, bindretval = -1; dcc->sok = socket (AF_INET, SOCK_STREAM, 0); if (dcc->sok == -1) return FALSE; memset (&SAddr, 0, sizeof (struct sockaddr_in)); len = sizeof (SAddr); getsockname (dcc->serv->sok, (struct sockaddr *) &SAddr, &len); SAddr.sin_family = AF_INET; /*if local_ip is specified use that*/ if (prefs.local_ip != 0) { my_addr = prefs.local_ip; SAddr.sin_addr.s_addr = prefs.local_ip; } /*otherwise use the default*/ else my_addr = SAddr.sin_addr.s_addr; /*if we have a valid portrange try to use that*/ if (prefs.first_dcc_send_port > 0) { SAddr.sin_port = 0; i = 0; while ((prefs.last_dcc_send_port > ntohs(SAddr.sin_port)) && (bindretval == -1)) { SAddr.sin_port = htons (prefs.first_dcc_send_port + i); i++; /*printf("Trying to bind against port: %d\n",ntohs(SAddr.sin_port));*/ bindretval = bind (dcc->sok, (struct sockaddr *) &SAddr, sizeof (SAddr)); } } /*if we didnt bind yet, try a random port*/ if (bindretval == -1) { SAddr.sin_port = 0; bindretval = bind (dcc->sok, (struct sockaddr *) &SAddr, sizeof (SAddr)); } if (bindretval == -1) { /* failed to bind */ PrintText (sess, "Failed to bind to any address or port.\n"); return FALSE; } len = sizeof (SAddr); getsockname (dcc->sok, (struct sockaddr *) &SAddr, &len); dcc->port = ntohs (SAddr.sin_port); /*if we have a dcc_ip, we use that, so the remote client can connect*/ /*we would tell the client to connect to our LAN ip otherwise*/ if (prefs.ip_from_server != 0 && prefs.dcc_ip != 0) dcc->addr = prefs.dcc_ip; else if (prefs.dcc_ip_str[0]) dcc->addr = inet_addr ((const char *) prefs.dcc_ip_str); else /*else we use the one we bound to*/ dcc->addr = my_addr; dcc->addr = ntohl (dcc->addr); set_nonblocking (dcc->sok); listen (dcc->sok, 1); set_blocking (dcc->sok); dcc->iotag = fe_input_add (dcc->sok, 1, 0, 1, dcc_accept, dcc); return TRUE;}static struct session *dccsess;static char *dccto; /* lame!! */static char *dcctbuf;static voiddcc_send_wild (char *file){ dcc_send (dccsess, dcctbuf, dccto, file);}/* tbuf is at least 400 bytes */voiddcc_send (struct session *sess, char *tbuf, char *to, char *file){ struct stat st; struct DCC *dcc = new_dcc (); if (!dcc) return; dcc->file = expand_homedir (file); if (strchr (dcc->file, '*') || strchr (dcc->file, '?')) { char path[256]; char wild[256]; strcpy (wild, file_part (dcc->file)); path_part (dcc->file, path); path[strlen (path) - 1] = 0; /* remove trailing slash */ dccsess = sess; dccto = to; dcctbuf = tbuf; for_files (path, wild, dcc_send_wild); dcc_close (dcc, 0, TRUE); return; } if (stat (dcc->file, &st) != -1) { if (*file_part (dcc->file) && !S_ISDIR (st.st_mode)) { if (st.st_size > 0) { dcc->offertime = time (0); dcc->serv = sess->server; dcc->dccstat = STAT_QUEUED; dcc->size = st.st_size; dcc->type = TYPE_SEND; dcc->fp = open (dcc->file, OFLAGS | O_RDONLY); if (dcc->fp != -1) { if (dcc_listen_init (dcc, sess)) { char havespaces = 0; file = dcc->file; while (*file) { if (*file == ' ') { if (prefs.dcc_send_fillspaces) *file = '_'; else havespaces = 1; } file++; } dcc->nick = strdup (to); if (prefs.autoopendccsendwindow) fe_dcc_open_send_win (TRUE); else fe_dcc_update_send_win (); if (havespaces) { snprintf (tbuf, 400, "PRIVMSG %s :\001DCC SEND \"%s\" %lu %d %d\001\r\n", to, file_part (dcc->file), dcc->addr, dcc->port, dcc->size); } else { snprintf (tbuf, 400, "PRIVMSG %s :\001DCC SEND %s %lu %d %d\001\r\n", to, file_part (dcc->file), dcc->addr, dcc->port, dcc->size); } tcp_send (sess->server, tbuf); EMIT_SIGNAL (XP_TE_DCCOFFER, sess, file_part (dcc->file), to, NULL, NULL, 0); } else { dcc_close (dcc, 0, TRUE); } return; } } } } snprintf (tbuf, 400, _("Cannot access %s\n"), dcc->file); PrintText (sess, tbuf); dcc_close (dcc, 0, TRUE);}static struct DCC *find_dcc_from_port (int port, int type){ struct DCC *dcc; GSList *list = dcc_list; while (list) { dcc = (struct DCC *) list->data; if (dcc->port == port && dcc->dccstat == STAT_QUEUED && dcc->type == type) return dcc; list = list->next; } return 0;}struct DCC *find_dcc (char *nick, char *file, int type){ GSList *list = dcc_list; struct DCC *dcc; while (list) { dcc = (struct DCC *) list->data; if (nick == NULL || !strcasecmp (nick, dcc->nick)) { if (type == -1 || dcc->type == type) { if (!file[0]) return dcc; if (!strcasecmp (file, file_part (dcc->file))) return dcc; if (!strcasecmp (file, dcc->file)) return dcc; } } list = list->next; } return 0;}/* called when we receive a NICK change from server */voiddcc_change_nick (struct server *serv, char *oldnick, char *newnick){ struct DCC *dcc; GSList *list = dcc_list; while (list) { dcc = (struct DCC *) list->data; if (dcc->serv == serv) { if (!strcasecmp (dcc->nick, oldnick)) { if (dcc->nick) free (dcc->nick); dcc->nick = strdup (newnick); } } list = list->next; }}voiddcc_get (struct DCC *dcc){ switch (dcc->dccstat) { case STAT_QUEUED: if (dcc->type != TYPE_CHATSEND) { dcc->resumable = 0; dcc->pos = 0; dcc_connect (dcc); } break; case STAT_DONE: case STAT_FAILED: case STAT_ABORTED: dcc_close (dcc, 0, TRUE); break; }}voiddcc_get_nick (struct session *sess, char *nick){ struct DCC *dcc; GSList *list = dcc_list; while (list) { dcc = (struct DCC *) list->data; if (!strcasecmp (nick, dcc->nick)) { if (dcc->dccstat == STAT_QUEUED && dcc->type == TYPE_RECV) { dcc->resumable = 0; dcc->pos = 0; dcc->ack = 0; dcc_connect (dcc); return; } } list = list->next; } if (sess) EMIT_SIGNAL (XP_TE_DCCIVAL, sess, NULL, NULL, NULL, NULL, 0);}static struct DCC *new_dcc (void){ struct DCC *dcc = malloc (sizeof (struct DCC)); if (!dcc) return 0; memset (dcc, 0, sizeof (struct DCC)); dcc->sok = -1; dcc->fp = -1; dcc_list = g_slist_prepend (dcc_list, dcc); return (dcc);}voiddcc_chat (struct session *sess, char *nick){ char outbuf[400]; struct DCC *dcc; dcc = find_dcc (nick, "", TYPE_CHATSEND); if (dcc) { switch (dcc->dccstat) { case STAT_ACTIVE: case STAT_QUEUED: case STAT_CONNECTING: EMIT_SIGNAL (XP_TE_DCCCHATREOFFER, sess, nick, NULL, NULL, NULL, 0); return; case STAT_ABORTED: case STAT_FAILED: dcc_close (dcc, 0, TRUE); } } dcc = find_dcc (nick, "", TYPE_CHATRECV); if (dcc) { switch (dcc->dccstat) { case STAT_QUEUED: dcc_connect (dcc); break; case STAT_FAILED: case STAT_ABORTED: dcc_close (dcc, 0, TRUE); } return; } /* offer DCC CHAT */ dcc = new_dcc (); if (!dcc) return; dcc->starttime = dcc->offertime = time (0); dcc->serv = sess->server; dcc->dccstat = STAT_QUEUED; dcc->type = TYPE_CHATSEND; dcc->nick = strdup (nick); if (dcc_listen_init (dcc, sess)) { if (prefs.autoopendccchatwindow) fe_dcc_open_chat_win (TRUE); else fe_dcc_update_chat_win (); snprintf (outbuf, sizeof (outbuf), "PRIVMSG %s :\001DCC CHAT chat %lu %d\001\r\n", nick, dcc->addr, dcc->port); tcp_send (dcc->serv, outbuf); EMIT_SIGNAL (XP_TE_DCCCHATOFFERING, sess, nick, NULL, NULL, NULL, 0); } else { dcc_close (dcc, 0, TRUE); }}static voiddcc_malformed (struct session *sess, char *nick, char *data){ EMIT_SIGNAL (XP_TE_MALFORMED_FROM, sess, nick, NULL, NULL, NULL, 0); EMIT_SIGNAL (XP_TE_MALFORMED_PACKET, sess, data, NULL, NULL, NULL, 0);}voiddcc_resume (struct DCC *dcc){ char tbuf[400]; if (dcc->dccstat == STAT_QUEUED && dcc->resumable) { if (strchr (dcc->file, ' ') != NULL) { /*filename contains spaces*/ snprintf (tbuf, sizeof (tbuf), "PRIVMSG %s :\001DCC RESUME \"%s\" %d %d\001\r\n", dcc->nick, dcc->file, dcc->port, dcc->resumable); } else { snprintf (tbuf, sizeof (tbuf), "PRIVMSG %s :\001DCC RESUME %s %d %d\001\r\n", dcc->nick, dcc->file, dcc->port, dcc->resumable); } tcp_send (dcc->serv, tbuf); }}voidhandle_dcc (struct session *sess, char *outbuf, char *nick, char *word[], char *word_eol[]){ struct DCC *dcc; char *type = word[5]; int port, size; unsigned long addr; if (!strcasecmp (type, "CHAT")) { port = atoi (word[8]); sscanf (word[7], "%lu", &addr); if (!addr || port < 1024) { dcc_malformed (sess, nick, word_eol[4] + 2); return; } dcc = find_dcc (nick, "", TYPE_CHATSEND); if (dcc) dcc_close (dcc, 0, TRUE); dcc = find_dcc (nick, "", TYPE_CHATRECV); if (dcc) dcc_close (dcc, 0, TRUE); dcc = new_dcc (); if (dcc) { dcc->serv = sess->server; dcc->type = TYPE_CHATRECV; dcc->dccstat = STAT_QUEUED; dcc->addr = addr; dcc->port = port; dcc->nick = strdup (nick); dcc->starttime = time (0); EMIT_SIGNAL (XP_TE_DCCCHATOFFER, sess->server->front_session, nick, NULL, NULL, NULL, 0); if (prefs.autoopendccchatwindow) fe_dcc_open_chat_win (TRUE); else fe_dcc_update_chat_win (); if (prefs.autodccchat) dcc_connect (dcc); } return; } if (!strcasecmp (type, "RESUME")) { port = atoi (word[7]); dcc = find_dcc_from_port (port, TYPE_SEND); if (!dcc) dcc = find_dcc (nick, word[6], TYPE_SEND); if (dcc) { dcc->resumable = atoi (word[8]); if (dcc->resumable < dcc->size) { dcc->pos = dcc->resumable; dcc->ack = dcc->resumable; lseek (dcc->fp, dcc->pos, SEEK_SET); if (strchr (file_part (dcc->file), ' ') != NULL) { /*filename contains spaces*/ snprintf (outbuf, 400, "PRIVMSG %s :\001DCC ACCEPT \"%s\" %d %d\001\r\n", dcc->nick, file_part (dcc->file), port, dcc->resumable); } else { snprintf (outbuf, 400, "PRIVMSG %s :\001DCC ACCEPT %s %d %d\001\r\n", dcc->nick, file_part (dcc->file), port, dcc->resumable); } tcp_send (dcc->serv, outbuf); } sprintf (outbuf, "%d", dcc->pos); EMIT_SIGNAL (XP_TE_DCCRESUMEREQUEST, sess, nick, file_part (dcc->file), outbuf, NULL, 0); } return; } if (!strcasecmp (type, "ACCEPT")) { port = atoi (word[7]); dcc = find_dcc_from_port (port, TYPE_RECV); if (dcc && dcc->dccstat == STAT_QUEUED) { dcc_connect (dcc); return; } } if (!strcasecmp (type, "SEND")) { char *file = file_part (word[6]); port = atoi (word[8]); size = atoi (word[9]); sscanf (word[7], "%lu", &addr); if (!addr || !size || port < 1024) { dcc_malformed (sess, nick, word_eol[4] + 2); return; } dcc = new_dcc (); if (dcc) { struct stat st; dcc->file = strdup (file); dcc->destfile = malloc (strlen (prefs.dccdir) + strlen (nick) + strlen (file) + 4); strcpy (dcc->destfile, prefs.dccdir); if (prefs.dccdir[strlen (prefs.dccdir) - 1] != '/') strcat (dcc->destfile, "/"); if (prefs.dccwithnick) { strcat (dcc->destfile, nick); strcat (dcc->destfile, "."); } strcat (dcc->destfile, file); dcc->resumable = 0; if (stat (dcc->destfile, &st) != -1) { if (st.st_size < size) dcc->resumable = st.st_size; } dcc->pos = dcc->resumable; dcc->serv = sess->server; dcc->type = TYPE_RECV; dcc->dccstat = STAT_QUEUED; dcc->addr = addr; dcc->port = port; dcc->size = size; dcc->nick = strdup (nick); if (prefs.autodccsend) { if (prefs.autoresume && dcc->resumable) { /* don't resume the same file from two people! */ GSList *list = dcc_list; struct DCC *d; while (list) { d = list->data; if (d->type == TYPE_RECV && d->dccstat != STAT_ABORTED && d->dccstat != STAT_DONE && d->dccstat != STAT_FAILED) { if (d != dcc && strcmp (d->destfile, dcc->destfile) == 0) goto dontresume; } list = list->next; } dcc_resume (dcc); } else {dontresume: dcc->resumable = 0; dcc->pos = 0; dcc_connect (dcc); } } if (prefs.autoopendccrecvwindow) fe_dcc_open_recv_win (TRUE); else fe_dcc_update_recv_win (); } sprintf (outbuf, "%d", size); EMIT_SIGNAL (XP_TE_DCCSENDOFFER, sess->server->front_session, nick, file, outbuf, NULL, 0); } else EMIT_SIGNAL (XP_TE_DCCGENERICOFFER, sess->server->front_session, word_eol[4] + 2, nick, NULL, NULL, 0);}voiddcc_show_list (struct session *sess, char *outbuf){ int i = 0; struct DCC *dcc; GSList *list = dcc_list; EMIT_SIGNAL (XP_TE_DCCHEAD, sess, NULL, NULL, NULL, NULL, 0); while (list) { dcc = (struct DCC *) list->data; i++; snprintf (outbuf, 255, " %-5.5s %-10.10s %-7.7s %-7d %-7d %s\n", dcctypes[(int) dcc->type], dcc->nick, _(dccstat[(int) dcc->dccstat].name), dcc->size, dcc->pos, file_part (dcc->file)); PrintText (sess, outbuf); list = list->next; } if (!i) PrintText (sess, _("No active DCCs\n"));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -