/* * dcc.c: Things dealing with client to client connections. * * Copyright(c) 1998 Colten Edwards aka panasync. * After alot of unhappiness with the old dcc.c code I took it upon myself * to rewrite this code. The only parts not greatly changed by myself was * code I had written by me in the first place. ie the ftp code and the * dcc botlink code. Some great improvements in dcc speed were realized * using non-blocking connects. All the previous dcc modes/commands are still * in place and available. */ #include "irc.h" static char cvsrevision[] = "$Id$"; CVS_REVISION(dcc_c) #include "struct.h" #include #include #include #include #include #ifdef HAVE_SYS_FILIO_H #include #endif #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) && !defined(__EMX__) # define IO_ARRAYLEN sysconf(_SC_OPEN_MAX) #else # ifdef FD_SETSIZE # define IO_ARRAYLEN FD_SETSIZE # else # define IO_ARRAYLEN NFDBITS # endif #endif #include "ctcp.h" #include "encrypt.h" #include "cdcc.h" #include "dcc.h" #include "hook.h" #include "ircaux.h" #include "lastlog.h" #include "list.h" #include "newio.h" #include "output.h" #include "parse.h" #include "server.h" #include "status.h" #include "vars.h" #include "who.h" #include "window.h" #include "screen.h" #include "ircterm.h" #include "hook.h" #include "misc.h" #include "tcl_bx.h" #include "userlist.h" #include "hash2.h" #include "gui.h" #define MAIN_SOURCE #include "modval.h" #include #ifdef WINNT #include #endif extern int use_socks; #define DCC_HASHSIZE 11 HashEntry dcc_no_flood[DCC_HASHSIZE]; struct _dcc_types_ { char *name; char *module; int type; int (*init_func)(); int (*open_func)(); int (*input)(); int (*output)(); int (*close_func)(); } _dcc_types[] = { {"", NULL, 0, NULL, NULL, NULL, NULL, NULL}, {"CHAT", NULL, DCC_CHAT, NULL, NULL, NULL, NULL, NULL}, {"SEND", NULL, DCC_FILEOFFER, NULL, NULL, NULL, NULL, NULL}, {"GET", NULL, DCC_FILEREAD, NULL, NULL, NULL, NULL, NULL}, {"RAW_LISTEN", NULL, DCC_RAW_LISTEN, NULL, NULL, NULL, NULL, NULL}, {"RAW", NULL, DCC_RAW, NULL, NULL, NULL, NULL, NULL}, {"RESEND", NULL, DCC_REFILEOFFER, NULL, NULL, NULL, NULL, NULL}, {"REGET", NULL, DCC_REFILEREAD, NULL, NULL, NULL, NULL, NULL}, {"BOT", NULL, DCC_BOTMODE, NULL, NULL, NULL, NULL, NULL}, {"FTP", NULL, DCC_FTPOPEN, NULL, NULL, NULL, NULL, NULL}, {"FTPGET", NULL, DCC_FTPGET, NULL, NULL, NULL, NULL, NULL}, {"FTPSEND", NULL, DCC_FTPSEND, NULL, NULL, NULL, NULL, NULL}, {NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL} }; struct _dcc_types_ **dcc_types = NULL; static char DCC_current_transfer_buffer[BIG_BUFFER_SIZE/4]; unsigned int send_count_stat = 0; unsigned int get_count_stat = 0; char *last_chat_req = NULL; static int dcc_quiet = 0; static int dcc_paths = 0; static int dcc_overwrite_var = 0; double dcc_bytes_in = 0; double dcc_bytes_out = 0; double dcc_max_rate_in = 0.0; static double dcc_min_rate_in = DBL_MAX; double dcc_max_rate_out = 0.0; static double dcc_min_rate_out = DBL_MAX; time_t dcc_timeout = 600; /* global /set dcc_timeout */ static int dcc_count = 0; /* new dcc handler */ #include "irc.h" #include "ircaux.h" #include "struct.h" #include "misc.h" extern Server *server_list; typedef struct _DCC_List { struct _DCC_List *next; char *nick; /* do NOT free this. it's a shared pointer. */ SocketList sock; } DCC_List; static DCC_List *pending_dcc = NULL; static void process_dcc_chat(int); #ifndef BITCHX_LITE static void process_dcc_bot(int); #endif static void start_dcc_chat(int); static unsigned char byte_order_test (void); static void dcc_update_stats(int); static void update_transfer(); static char *strip_path(char *); static void dcc_getfile_resume_demanded(char *, char *, char *, char *); static void dcc_getfile_resume_start (char *, char *, char *, char *); static void output_reject_ctcp (UserhostItem *, char *, char *); extern int use_nat_address; extern struct in_addr nat_address; #if 0 /* sock num, type, address, port */ int (*dcc_open_func) (int, int, struct sockaddr_foobar, int) = NULL; /* type, sock num, buffer, buff_len */ int (*dcc_output_func) (int, int, char *, int) = NULL; /* sock num, type, buffer, new line, len buffer */ int (*dcc_input_func) (int, int, char *, int, int) = NULL; /* socket num, address, port */ int (*dcc_close_func) (int, sockaddr_foobar, int) = NULL; #endif #define DCC_OPEN 1 #define DCC_INPUT 2 #define DCC_OUTPUT 3 #define DCC_CLOSE 4 static int check_dcc_init(char *nick, char *type, char *description, char *address, char *port, char *size, char *extra, char *uhost); /* bind type, sock num, type, address, port, buffer, buflen , newline */ #ifndef O_BINARY #define O_BINARY 0 #endif #define BAR_LENGTH 60 typedef struct { char * name; dcc_function function; char * help; } DCC_commands; DCC_dllcommands *dcc_dllcommands = NULL; void dcc_chat(char *command, char *args); void BX_dcc_filesend(char *command, char *args); void BX_dcc_resend(char *command, char *args); void dcc_getfile(char *command, char *args); void dcc_regetfile(char *command, char *args); void dcc_glist(char *command, char *args); void dcc_resume(char *command, char *args); void dcc_rename(char *command, char *args); void dcc_show_active(char *command, char *args); void dcc_set_quiet(char *command, char *args); void dcc_set_paths(char *command, char *args); void dcc_tog_rename(char *command, char *args); void dcc_tog_resume(char *command, char *args); void dcc_overwrite_toggle(char *command, char *args); void dcc_tog_auto(char *command, char *args); void dcc_stats(char *command, char *args); void dcc_close(char *command, char *args); void dcc_closeall(char *command, char *args); void dcc_help1(char *command, char *args); void dcc_exempt(char *command, char *args); void dcc_ftpopen(char *command, char *args); DCC_commands dcc_commands[] = { #ifndef BITCHX_LITE { "BOT", dcc_chat, NULL }, #endif { "CHAT", dcc_chat, "[nick]\n- Starts a dcc chat connection" }, { "CLOSE", dcc_close, NULL }, { "CLOSEALL", dcc_closeall, NULL }, { "SEND", BX_dcc_filesend, "[-b block] [-e passwd] [-p port] [nick|nick1,nick2] filename(s)\n- Send list of files to nick(s)" }, { "RESEND", BX_dcc_resend, "[-b block] [-e passwd] [-p port] [nick|nick1,nick2] filename(s)\n- Send list of files to nick(s)" }, { "TSEND", BX_dcc_filesend, "[-b block] [-e passwd] [-p port] [nick|nick1,nick2] filename(s)\n- Send list of files to nick(s)" }, { "TRESEND", BX_dcc_resend, "[-b block] [-e passwd] [-p port] [nick|nick1,nick2] filename(s)\n- Send list of files to nick(s)" }, #ifdef MIRC_BROKEN_DCC_RESUME { "RESUME", dcc_resume, NULL }, #endif { "GET", dcc_getfile, NULL }, { "REGET", dcc_regetfile, NULL }, { "TGET", dcc_getfile, NULL }, { "TREGET", dcc_regetfile, NULL }, { "LIST", dcc_glist, NULL }, { "FTP", dcc_ftpopen, NULL }, { "RENAME", dcc_rename, "nick filename" }, { "ACTIVECOUNT",dcc_show_active, NULL }, { "QUIETMODE", dcc_set_quiet, NULL }, { "SHOWPATHS", dcc_set_paths, NULL }, { "AUTORENAME", dcc_tog_rename, NULL }, { "AUTORESUME", dcc_tog_resume, NULL }, { "AUTOOVERWRITE",dcc_overwrite_toggle, NULL }, { "AUTOGET", dcc_tog_auto, NULL }, { "STATS", dcc_stats, NULL }, { "EXEMPT", dcc_exempt, NULL }, { "HELP", dcc_help1, NULL }, { NULL, (dcc_function) NULL, NULL } }; static int doing_multi = 0; /* * set this if doing multiple requests * helps prevent console spam by reducing * the amount of output. */ #if 0 int add_dcc_command(char *name, char *help, void (*func)(char *, char *)) { int count = 0; if (!dcc_dllcommands) /* ooh first time. need to init. make it double*/ dcc_dllcommands = new_malloc(sizeof(DCC_commands) * 2); else { for ( ; dcc_dllcommands[count].name; count++) ; RESIZE(dcc_dllcommands, DCC_commands, count + 2); } malloc_strcpy(&dcc_dllcommands[count].name, name); malloc_strcpy(&dcc_dllcommands[count].help, help); dcc_dllcommands[count].function = func; return count + 1; } int remove_dcc_hook(char *name) { int i, count = 0; int done = 0; for ( ; dcc_dllcommands[count].name; count++) ; for (i = 0; i < count; i++) { if (dcc_dllcommands[i].name && !my_stricmp(dcc_dllcommands[i].name, name)) { new_free(&dcc_dllcommands[i].name); new_free(&dcc_dllcommands[i].help); dcc_dllcommands[i].function = NULL; done++; break; } } return done; } #endif void send_ctcp_booster(char *nick, char *type, char *file, unsigned long address, unsigned short portnum, unsigned long filesize) { if (filesize) send_ctcp(CTCP_PRIVMSG, nick, CTCP_DCC, "%s %s %lu %u %lu", type, file,address, portnum, filesize); else send_ctcp(CTCP_PRIVMSG, nick, CTCP_DCC, "%s %s %lu %u", type, file, address, portnum); } void send_reject_ctcp(char *nick, char *type, char *name) { /* * And output it to the user */ userhostbase(nick, output_reject_ctcp, 1, "%s %s %s", nick, type, name ? name : ""); } void BX_erase_dcc_info(int s, int reject, char *format, ...) { DCC_int *n = NULL; SocketList *s1; static time_t last_reject = 0; if (format) { va_list args; char buffer[BIG_BUFFER_SIZE+1]; va_start(args, format); vsnprintf(buffer, BIG_BUFFER_SIZE, format, args); va_end(args); put_it("%s", buffer); } dcc_update_stats(s); s1 = get_socket(s); if (check_dcc_socket(s) && (n = (DCC_int *)get_socketinfo(s))) { if (dcc_types[s1->flags & DCC_TYPES]->close_func) (*dcc_types[s1->flags & DCC_TYPES]->close_func)(s, n->remote.s_addr, n->remport); if (reject && ((now - last_reject) < 2)) send_reject_ctcp(s1->server, (((s1->flags & DCC_TYPES) == DCC_FILEOFFER) ? "GET" : ((s1->flags & DCC_TYPES) == DCC_FILEREAD) ? "SEND" : dcc_types[s1->flags & DCC_TYPES]->name), n->filename); last_reject = now; new_free(&n->user); new_free(&n->userhost); new_free(&n->encrypt); new_free(&n->filename); new_free(&n->othername); if (n->file > 0) close(n->file); new_free(&n); } set_socketinfo(s, NULL); update_transfer(); dcc_count--; /* dcc_renumber_active();*/ } /* dcc_match() * * Returns non-zero if the passed DCC socket matches the supplied parameters. * NULL for string parameters and -1 for int parameters means Don't-Care. */ static int dcc_match(const SocketList *s, const char *nick, const char *desc, const char *other, int type, int active, int num) { const DCC_int *n = s->info; if (type != -1 && type != (s->flags & DCC_TYPES)) return 0; if (num != -1 && num != n->dccnum) return 0; if (nick && my_stricmp(nick, s->server)) return 0; if (desc && n->filename && my_stricmp(desc, n->filename)) { const char *last = strrchr(n->filename, '/'); if (!last || my_stricmp(desc, last + 1)) return 0; } if (other && n->othername && my_stricmp(other, n->othername)) return 0; if (active == 0 && (s->flags & DCC_ACTIVE)) return 0; if (active == 1 && !(s->flags & DCC_ACTIVE)) return 0; return 1; } /* * finds an active dcc connection. one that either is already started * or one that has been initiated on our side. */ SocketList *BX_find_dcc(const char *nick, const char *desc, const char *other, int type, int create, int active, int num) { int i; SocketList *s; for (i = 0; i < get_max_fd()+1; i++) { if (!check_dcc_socket(i)) continue; s = get_socket(i); if (dcc_match(s, nick, desc, other, type, active, num)) return s; } return NULL; } /* * finds a pending dcc which the other end has initiated. */ static DCC_List *find_dcc_pending(const char *nick, const char *desc, const char *othername, int type, int remove, int num) { SocketList *s; DCC_List *new_i; DCC_List *last_i = NULL; for (new_i = pending_dcc; new_i; last_i = new_i, new_i = new_i->next) { s = &new_i->sock; if (dcc_match(s, nick, desc, othername, type, -1, num)) { if (remove) { if (last_i) last_i->next = new_i->next; else pending_dcc = new_i->next; } return new_i; } } return NULL; } void add_userhost_to_chat(UserhostItem *stuff, char *nick, char *args) { SocketList *Client = NULL; if (!stuff || !stuff->nick || !stuff->user || !stuff->host || !strcmp(stuff->user, "")) return; if ((Client = find_dcc(nick, "chat", NULL, DCC_CHAT, 0, -1, -1))) { DCC_int *n = Client->info; n->userhost = m_sprintf("%s@%s", stuff->user, stuff->host); n->server = from_server; } return; } static void refileread_send_start(int s, DCC_int *n) { struct stat buf; lseek(n->file, 0, SEEK_END); /* get the size of our file to be resumed */ fstat(n->file, &buf); n->transfer_orders.packet_id = DCC_PACKETID; n->transfer_orders.byteoffset = buf.st_size; n->transfer_orders.byteorder = byte_order_test(); put_it("%s", convert_output_format("$G %RDCC %YTelling uplink we want to start at%n: $0", "%s", ulongcomma(n->transfer_orders.byteoffset))); send(s, (const char *)&n->transfer_orders, sizeof(struct transfer_struct), 0); } #ifdef HAVE_SSL int SSL_dcc_create(SocketList *s, int sock, int doconnect) { set_blocking(sock); if(doconnect) s->ctx = SSL_CTX_new (SSLv23_client_method()); else s->ctx = SSL_CTX_new (SSLv23_server_method()); SSL_CTX_set_cipher_list(s->ctx, "ADH:@STRENGTH"); s->ssl_fd = SSL_new (s->ctx); SSL_set_fd (s->ssl_fd, sock); if(doconnect) return SSL_connect (s->ssl_fd); return SSL_accept(s->ssl_fd); } #endif DCC_int *BX_dcc_create(char *nick, char *filename, char *passwd, unsigned long filesize, int port, int type, unsigned long flags, void (*func)(int)) { struct sockaddr_foobar myip, blah; int ofs = from_server; int s; DCC_int *new = NULL; DCC_List *new_i; if (from_server == -1) from_server = get_window_server(0); if (from_server == -1) return NULL; if (get_int_var(DCC_USE_GATEWAY_ADDR_VAR)) blah = get_server_uh_addr(from_server); else blah = get_server_local_addr(from_server); memcpy(&myip, &blah, sizeof(struct sockaddr_foobar)); if (use_nat_address) { myip.sf_family = AF_INET; myip.sf_addr.s_addr = nat_address.s_addr; } set_display_target(NULL, LOG_DCC); if ( ((new_i = find_dcc_pending(nick, filename, NULL, type, 1, -1)) && new_i->sock.flags & DCC_OFFER) || (flags & DCC_OFFER)) { SocketList *s = NULL; int new_s; struct sockaddr_in remaddr; socklen_t rl = sizeof(remaddr); if (!new_i && !(new_i = find_dcc_pending(nick, filename, NULL, type, 1, -1))) return NULL; s = &new_i->sock; new = (DCC_int *)s->info; if ((new_s = connect_by_number(inet_ntoa(new->remote), &new->remport, SERVICE_CLIENT, PROTOCOL_TCP, 0)) < 0 #ifdef HAVE_SSL || (flags & DCC_SSL ? SSL_dcc_create(s, new_s, 1) : 0) < 0 #endif ) { #ifdef HAVE_SSL SSL_show_errors(); #endif erase_dcc_info(s->is_read, 1, "%s", convert_output_format("$G %RDCC%n Unable to create connection: $0-", "%s", errno ? strerror(errno) : "Unknown Host")); close_socketread(s->is_read); from_server = ofs; new_free(&new_i->nick); new_free(&new_i); reset_display_target(); return NULL; } flags |= DCC_ACTIVE; add_socketread(new_s, new->remport, flags|type, nick, new_i->sock.func_read, NULL); set_socketinfo(new_s, new); if ((getpeername(new_s, (struct sockaddr *) &remaddr, &rl)) != -1) { flags &= ~DCC_OFFER; if (type != DCC_RAW) { int blah; if (type == DCC_FILEOFFER) blah = do_hook(DCC_CONNECT_LIST,"%s %s %s %d %ld %s", nick, dcc_types[type]->name, inet_ntoa(remaddr.sin_addr), ntohs(remaddr.sin_port),(unsigned long)new->filesize, new->filename); else blah = do_hook(DCC_CONNECT_LIST,"%s %s %s %d", nick, dcc_types[type]->name, inet_ntoa(remaddr.sin_addr), ntohs(remaddr.sin_port)); if (blah && !dcc_quiet) put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_CONNECT_FSET), "%s %s %s %s %s %d", update_clock(GET_TIME), dcc_types[type]->name, nick, new->userhost?new->userhost:"u@h", inet_ntoa(remaddr.sin_addr), (int)ntohs(remaddr.sin_port))); } } if (dcc_types[type]->open_func) (*dcc_types[type]->open_func)(new_s, type, new->remote.s_addr, ntohs(remaddr.sin_port)); if (type == DCC_REFILEREAD) refileread_send_start(new_s, new); if (get_int_var(DCC_FAST_VAR) #ifdef HAVE_SSL && !(flags & DCC_SSL) #endif ) { set_non_blocking(new_s); new->dcc_fast = 1; } set_socketflags(new_s, flags|type); get_time(&new->starttime); get_time(&new->lasttime); new_free(&new_i->nick); new_free(&new_i); } else { char *nopath = NULL; char *file = NULL; char *Type; unsigned short portnum = port; /* If a port isn't specified and random local ports is on * generate a random port to use. */ if (!port && get_int_var(RANDOM_LOCAL_PORTS_VAR)) portnum = random_number(0) % (65536 - 1024) + 1024; if (get_int_var(DCC_FORCE_PORT_VAR)) portnum = get_int_var(DCC_FORCE_PORT_VAR); flags |= DCC_WAIT; if ((s = connect_by_number(NULL, &portnum, SERVICE_SERVER, PROTOCOL_TCP, 1)) < 0) { /* If a port was specified and we failed, and * random local ports is on, try a random port. */ if(port && get_int_var(RANDOM_LOCAL_PORTS_VAR)) portnum = random_number(0) % (65536 - 1024) + 1024; else portnum = 0; if ((s = connect_by_number(NULL, &portnum, SERVICE_SERVER, PROTOCOL_TCP, 1)) < 0) { /* Finally try to get a system port number by using 0 */ portnum = 0; s = connect_by_number(NULL, &portnum, SERVICE_SERVER, PROTOCOL_TCP, 1); } } if (s < 0) { put_it("%s", convert_output_format("$G %RDCC%n Unable to create connection: $0-", "%s", errno ? strerror(errno) : "Unknown Host")); reset_display_target(); from_server = ofs; return NULL; } Type = dcc_types[type]->name; add_socketread(s, portnum, flags|type, nick, func, NULL); add_sockettimeout(s, 120, NULL); new = new_malloc(sizeof(DCC_int)); new->struct_type = DCC_STRUCT_TYPE; new->othername = m_strdup(ltoa(portnum)); new->localport = port; new->dccnum = ++dcc_count; get_time(&new->lasttime); set_socketinfo(s, new); if (!(flags & DCC_TWOCLIENTS)) { reset_display_target(); from_server = ofs; return new; } if (passwd) new->encrypt = m_strdup(passwd); if (filename) { char *p; if ((nopath = strrchr(filename, '/'))) nopath++; else nopath = filename; file = LOCAL_COPY(nopath); p = file; while ((p = strchr(p, ' '))) *p = '_'; if (strcmp(filename, "bxglobal")) new->filename = m_strdup(filename); else new->filename = m_strdup("_bxglobal"); } new->filesize = filesize; #if 0 if (use_socks && get_string_var(SOCKS_HOST_VAR)) { struct hostent *hp; struct sockaddr_in socks; unsigned long addr; hp = gethostbyname(get_string_var(SOCKS_HOST_VAR)); memcpy(&socks, hp->h_addr, sizeof(hp->h_length)); addr = inet_addr(inet_ntoa(socks.sin_addr)); send_ctcp_booster(nick, Type, file, addr, portnum, filesize); } else #endif send_ctcp_booster(nick, Type, file, ntohl(myip.sf_addr.s_addr), portnum, filesize); if (!doing_multi && !dcc_quiet) { if (filesize) { if (do_hook(DCC_OFFER_LIST, "%s %s %s %lu", nick, Type, file, filesize)) put_it("%s", convert_output_format(fget_string_var(FORMAT_SEND_DCC_CHAT_FSET), "%s %s %s", update_clock(GET_TIME), Type, nick)); } else { if (do_hook(DCC_OFFER_LIST, "%s %s %s", nick, Type, file)) put_it("%s", convert_output_format(fget_string_var(FORMAT_SEND_DCC_CHAT_FSET), "%s %s %s", update_clock(GET_TIME), Type, nick)); } } } reset_display_target(); from_server = ofs; return new; } static void start_dcc_chat(int s) { struct sockaddr_in remaddr; socklen_t sra; int type; int new_s = -1; char *nick = NULL; unsigned long flags; DCC_int *n = NULL; SocketList *sa, *new_sa; void (*func)(int) = process_dcc_chat; sa = get_socket(s); flags = sa->flags; nick = sa->server; sra = sizeof(struct sockaddr_in); new_s = my_accept(s, (struct sockaddr *) &remaddr, &sra); type = flags & DCC_TYPES; n = get_socketinfo(s); n->user = m_strdup(nick); set_display_target(NULL, LOG_DCC); #ifndef BITCHX_LITE if (type == DCC_BOTMODE) func = process_dcc_bot; #endif if ((add_socketread(new_s, ntohs(remaddr.sin_port), flags, nick, func, NULL)) < 0) { erase_dcc_info(s, 0, "%s", convert_output_format("$G %RDCC error: accept() failed. punt!!", NULL, NULL)); close_socketread(s); return; } flags &= ~DCC_WAIT; flags |= DCC_ACTIVE; set_socketflags(new_s, flags); set_socketinfo(new_s, n); new_sa = get_socket(new_s); #ifdef HAVE_SSL if((flags & DCC_SSL) && SSL_dcc_create(new_sa, new_s, 0) < 0) { say("SSL_accept failed."); SSL_show_errors(); return; } #endif if (do_hook(DCC_CONNECT_LIST, "%s %s %s %d", nick, dcc_types[type]->name, inet_ntoa(remaddr.sin_addr), ntohs(remaddr.sin_port))) put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_CONNECT_FSET), "%s %s %s %s %s %d", update_clock(GET_TIME), dcc_types[type]->name, nick, n->userhost?n->userhost:"u@h", inet_ntoa(remaddr.sin_addr),ntohs(remaddr.sin_port))); if ((type == DCC_BOTMODE) && n->encrypt) new_free(&n->encrypt); get_time(&n->starttime); close_socketread(s); if (dcc_types[type]->open_func) (*dcc_types[type]->open_func)(new_s, type, n->remote.s_addr, ntohs(remaddr.sin_port)); reset_display_target(); } static void process_dcc_chat(int s) { unsigned long flags; char tmp[BIG_BUFFER_SIZE+1]; char *bufptr; long bytesread; char *nick; int type; SocketList *sl; flags = get_socketflags(s); nick = get_socketserver(s); type = flags & DCC_TYPES; sl = get_socket(s); bufptr = tmp; if (dcc_types[type]->input) bytesread = (*dcc_types[type]->input)(s, type, bufptr, 1, BIG_BUFFER_SIZE); else #ifdef HAVE_SSL bytesread = dgets(bufptr, s, 1, BIG_BUFFER_SIZE, sl->ssl_fd); #else bytesread = dgets(bufptr, s, 1, BIG_BUFFER_SIZE, NULL); #endif set_display_target(nick, LOG_DCC); switch(bytesread) { case -1: { const char *real_tmp = dgets_strerror(dgets_errno); if (do_hook(DCC_LOST_LIST, "%s %s %s", nick, dcc_types[type]->name, real_tmp)) put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_ERROR_FSET), "%s %s %s %s", update_clock(GET_TIME), dcc_types[type]->name, nick, real_tmp)); erase_dcc_info(s, 1, NULL); close_socketread(s); break; } case 0: break; default: { char *equal_nickname = NULL; char *uhost, *p; DCC_int *n = NULL; n = get_socketinfo(s); if ((p = strrchr(tmp, '\r'))) *p = 0; if ((p = strrchr(tmp, '\n'))) *p = 0; my_decrypt(tmp, strlen(tmp), n->encrypt); n->bytes_read += bytesread; set_display_target(nick, LOG_DCC); uhost = alloca(200); *uhost = 0; if (n->userhost) uhost = n->userhost; else strmopencat(uhost, 99, "Unknown@", "unknown"/*inet_ntoa(remaddr.sin_addr)*/, NULL); FromUserHost = uhost; #ifndef BITCHX_LITE if (*tmp == DEFAULT_BOTCHAR) { char *pc; pc = tmp+1; if ((flags & DCC_BOTCHAT)) { if (my_strnicmp(pc, "chat", 4)) { if (check_tcl_dcc(pc, nick, n->userhost?n->userhost:empty_string, s)) break; } } else if (!my_strnicmp(pc, "chat", 4) && check_tcl_dcc(pc, nick, n->userhost?n->userhost:empty_string, s)) break; } else if (get_int_var(BOT_MODE_VAR) && !(flags & DCC_BOTCHAT)) { extern int cmd_password(int, char *); if (cmd_password(s, tmp)) { dcc_printf(s, "Wrong Password\n"); erase_dcc_info(sl->is_read, 1, NULL); close_socketread(sl->is_read); } break; } #endif #undef CTCP_REPLY #define CTCP_MESSAGE "CTCP_MESSAGE " #define CTCP_MESSAGE_LEN strlen(CTCP_MESSAGE) #define CTCP_REPLY "CTCP_REPLY " #define CTCP_REPLY_LEN strlen(CTCP_REPLY) equal_nickname = alloca(strlen(nick) + 10); *equal_nickname = 0; strmopencat(equal_nickname, strlen(nick)+4, "=", nick, NULL); if (!strncmp(tmp, CTCP_MESSAGE, CTCP_MESSAGE_LEN) || (*tmp == CTCP_DELIM_CHAR && !strncmp(tmp+1, "ACTION", 6))) { char *tmp2; tmp2 = LOCAL_COPY(tmp); strcpy(tmp, do_ctcp(equal_nickname, get_server_nickname(from_server), stripansicodes((tmp2 + ((*tmp2 == CTCP_DELIM_CHAR) ? 0 : CTCP_MESSAGE_LEN)) ) )); if (!*tmp) break; } else if (!strncmp(tmp, CTCP_REPLY, CTCP_REPLY_LEN) || *tmp == CTCP_DELIM_CHAR) { char *tmp2; tmp2 = LOCAL_COPY(tmp); strcpy(tmp, do_notice_ctcp(equal_nickname, get_server_nickname(from_server), stripansicodes(tmp2 + (((*tmp2 == CTCP_DELIM_CHAR) ? 0 : CTCP_REPLY_LEN))))); if (!*tmp) break; } if (do_hook(DCC_CHAT_LIST, "%s %s", nick, tmp)) { addtabkey(equal_nickname, "msg", 0); put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_CHAT_FSET), "%s %s %s %s", update_clock(GET_TIME), nick, FromUserHost, tmp)); add_last_type(&last_dcc[0], MAX_LAST_MSG, nick, NULL, FromUserHost, tmp); logmsg(LOG_DCC, nick, 0, "%s", tmp); } FromUserHost = empty_string; break; } } reset_display_target(); } #ifndef BITCHX_LITE static void process_dcc_bot(int s) { unsigned long flags; char tmp[BIG_BUFFER_SIZE+1]; char *bufptr; long bytesread; char *nick; int type; SocketList *sl; flags = get_socketflags(s); nick = get_socketserver(s); type = flags & DCC_TYPES; sl = get_socket(s); bufptr = tmp; if (dcc_types[type]->input) bytesread = (*dcc_types[type]->input) (type, s, bufptr, 1, BIG_BUFFER_SIZE); else #ifdef HAVE_SSL bytesread = dgets(bufptr, s, 1, BIG_BUFFER_SIZE, sl->ssl_fd); #else bytesread = dgets(bufptr, s, 1, BIG_BUFFER_SIZE, NULL); #endif set_display_target(nick, LOG_DCC); switch(bytesread) { case -1: { const char *real_tmp = dgets_strerror(dgets_errno); if (do_hook(DCC_LOST_LIST, "%s %s %s", nick, dcc_types[type]->name, real_tmp)) put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_ERROR_FSET), "%s %s %s %s", update_clock(GET_TIME), dcc_types[type]->name, nick, real_tmp)); erase_dcc_info(s, 1, NULL); close_socketread(s); break; } case 0: break; default: { DCC_int *n = NULL; char *p; n = get_socketinfo(s); if ((p = strrchr(tmp, '\r'))) *p = 0; if ((p = strrchr(tmp, '\n'))) *p = 0; my_decrypt(tmp, strlen(tmp), n->encrypt); n->bytes_read += bytesread; set_display_target(nick, LOG_DCC); handle_dcc_bot(s, tmp); } } reset_display_target(); } #endif /* flag == 1 means show it. flag == 0 used by redirect (and /ctcp) */ static void new_dcc_message_transmit (char *user, char *text, char *text_display, int type, int flag, char *cmd, int check_host) { SocketList *s = NULL; DCC_int *n = NULL; char tmp[MAX_DCC_BLOCK_SIZE+1]; int list = 0; int len = 0; char *host = NULL; char thing = 0; *tmp = 0; switch(type) { case DCC_CHAT: thing = '='; host = "chat"; list = SEND_DCC_CHAT_LIST; break; case DCC_RAW: if (check_host) { if (!(host = next_arg(text, &text))) { put_it("%s", convert_output_format("$G %RDCC%n No host specified for DCC RAW", NULL, NULL)); return; } } break; } s = find_dcc(user, host, NULL, type, 0, 1, -1); if (!s || !(s->flags & DCC_ACTIVE)) { put_it("%s", convert_output_format("$G %RDCC No active $0:$1 connection for $2", "%s %s %s", dcc_types[type]->name, host?host:"(null)", user)); return; } n = (DCC_int *)s->info; /* * Check for CTCPs... whee. */ if (cmd && *text == CTCP_DELIM_CHAR && strncmp(text+1, "ACTION", 6)) { if (!strcmp(cmd, "PRIVMSG")) strlcpy(tmp, "CTCP_MESSAGE ", sizeof tmp); else strlcpy(tmp, "CTCP_REPLY ", sizeof tmp); } strmcat(tmp, text, n->blocksize-3); strmcat(tmp, "\n", n->blocksize-2); len = strlen(tmp); my_encrypt(tmp, len, n->encrypt); if (dcc_types[type]->output) (*dcc_types[type]->output) (type, s->is_read, tmp, len); else #ifdef HAVE_SSL if(s->ssl_fd) SSL_write(s->ssl_fd, tmp, len); else #endif write(s->is_read, tmp, len); n->bytes_sent += len; if (flag && type != DCC_RAW) { if (do_hook(list, "%s %s", user, text_display ? text_display : text)) put_it("%s", convert_output_format(fget_string_var(FORMAT_SEND_DCC_CHAT_FSET), "%c %s %s", thing, user, text_display?text_display:text)); } } extern void dcc_chat_transmit (char *user, char *text, char *orig, char *type, int noisy) { int fd; /* * This is just a quick hack. Its not fast, its not elegant, * and its not the best way to do this. But i whipped it up in * 15 minutes. The "best" soLution is to rewrite dcc_message_transmit * to allow us to do this sanely. */ set_display_target(NULL, LOG_DCC); if ((fd = atol(user))) { SocketList * s; char * bogus; if (!check_dcc_socket(fd)) { put_it("%s", convert_output_format("$G %RDCC%n Descriptor [$0] is not an open DCC RAW", "%d", fd)); return; } s = get_socket(fd); bogus = alloca(strlen(text) + strlen(((DCC_int *)s->info)->filename) + 3); strcpy(bogus, ((DCC_int *)s->info)->filename); strcat(bogus, space); strcat(bogus, text); new_dcc_message_transmit(user, bogus, orig, DCC_RAW, noisy, type, 0); } else new_dcc_message_transmit(user, text, orig, DCC_CHAT, noisy, type, 0); reset_display_target(); } extern void dcc_bot_transmit (char *user, char *text, char *type) { set_display_target(user, LOG_DCC); new_dcc_message_transmit(user, text, NULL, DCC_BOTMODE, 0, type, 1); reset_display_target(); } extern void dcc_chat_transmit_quiet (char *user, char *text, char *type) { new_dcc_message_transmit(user, text, NULL, DCC_CHAT, 0, type, 0); } int dcc_activechat(char *user) { return find_dcc(user, NULL, NULL, DCC_CHAT, 0, 1, -1) ? 1 : 0; } int dcc_activebot(char *user) { return find_dcc(user, NULL, NULL, DCC_BOTMODE, 0, 1, -1) ? 1 : 0; } int dcc_activeraw(char *user) { return find_dcc(user, NULL, NULL, DCC_RAW, 0, 1, -1) ? 1 : 0; } int get_dcc_type(char *type) { int tdcc = 0; int i; if (!type || !*type) return -1; upper(type); if (*type == 'T') type++, tdcc = DCC_TDCC; for (i = 0; dcc_types[i]->name; i++) if (!strcmp(type, dcc_types[i]->name)) return i | tdcc; return -1; } void process_dcc_send1(int s); void start_dcc_get(int s); /* dcc_fullname() * Return an allocated string with the full pathname to a DCC downloaded file. */ static char *dcc_fullname(const char *filename) { char *fullname; if (get_string_var(DCC_DLDIR_VAR)) { char *tmp = m_sprintf("%s/%s", get_string_var(DCC_DLDIR_VAR), filename); fullname = expand_twiddle(tmp); new_free(&tmp); } else { fullname = m_strdup(filename); } return fullname; } static int parse_offer_params(const char *address, const char *port, const char *size, unsigned long *p_addr, unsigned int *p_port, unsigned long *p_filesize) { if (size && *size) *p_filesize = atol(size); else *p_filesize = 0; *p_addr = strtoul(address, NULL, 10); *p_port = (unsigned)strtoul(port, NULL, 10); if (*p_port < 1024) { put_it("%s", convert_output_format("$G %RDCC%n Privileged port attempt [$0]", "%d", *p_port)); return 0; } if (*p_addr == 0) { struct in_addr in; in.s_addr = htonl(*p_addr); put_it("%s", convert_output_format("$G %RDCC%n Handshake ignored because of 0 port or address [$0:$1]", "%d %s", *p_port, inet_ntoa(in))); return 0; } return 1; } static int check_collision(char *nick, const char *description, int type) { SocketList *s = find_dcc(nick, description, NULL, type, 0, -1, -1); if (s) { if ((s->flags & DCC_ACTIVE)) { /* collision. */ put_it("%s", convert_output_format("$G %RDCC%n Received DCC $0 request from $1 while previous session active", "%s %s", type, nick)); return 0; } if ((s->flags & DCC_WAIT)) { if (type == DCC_CHAT) { if (do_hook(DCC_CONNECT_LIST,"%s CHAT %s",nick, "already requested connecting")) put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_CONNECT_FSET), "%s %s %s %s %s %d", update_clock(GET_TIME), "CHAT", nick, space, "already requested connecting...", 0)); dcc_chat(NULL, nick); return 0; } send_ctcp(CTCP_NOTICE, nick, CTCP_DCC, "DCC %s collision occured while connecting to %s (%s)", type, nickname, description); erase_dcc_info(s->is_read, 1, "%s", convert_output_format("$G %RDCC%n $0 collision for $1:$2", "%s %s %s", type, nick, description)); close_socketread(s->is_read); return 0; } } return 1; } static DCC_int *create_dcc_int(const char *nick, const char *description, const char *userhost, unsigned long address, unsigned short port, unsigned long filesize, int server) { UserList *ul = NULL; DCC_int *n = new_malloc(sizeof *n); #ifdef WANT_USERLIST ul = lookup_userlevelc(nick, userhost, "*", NULL); #endif if (userhost) n->userhost = m_strdup(userhost); n->ul = ul; n->remport = port; n->remote.s_addr = htonl(address); n->filesize = filesize; n->filename = m_strdup(description); n->user = m_strdup(nick); n->blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); n->server = server; n->file = -1; /* just in case */ n->struct_type = DCC_STRUCT_TYPE; return n; } static DCC_List *add_dcc_pending(DCC_int *dcc, int flags, void (*func_read)(int)) { DCC_List *new_d = new_malloc(sizeof *new_d); new_d->sock.info = dcc; new_d->sock.server = new_d->nick = m_strdup(dcc->user); new_d->sock.port = dcc->remport; new_d->sock.flags = flags; new_d->sock.time = now + dcc_timeout; new_d->sock.func_read = func_read; /* point this to the startup function */ new_d->next = pending_dcc; pending_dcc = new_d; return new_d; } /* show_dcc_offer() * Wrapper to show the user using the default format a non-file (eg. CHAT) DCC offer. */ static void show_dcc_offer(const char *nick, const char *dcc_name, const char *description, const char *userhost, unsigned long offer_addr, unsigned int offer_port) { if (!dcc_quiet) { struct in_addr in; in.s_addr = htonl(offer_addr); put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_REQUEST_FSET), "%s %s %s %s %s %s %d", update_clock(GET_TIME), dcc_name, description, nick, userhost, inet_ntoa(in), offer_port)); } if (beep_on_level & LOG_DCC) beep_em(1); } /* show_dcc_fileoffer() * Wrapper to show the user using the default format a file (eg. SEND) DCC offer. */ static void show_dcc_fileoffer(const char *nick, const char *dcc_name, const char *description, const char *userhost, unsigned long offer_addr, unsigned int offer_port, unsigned long filesize) { if (!dcc_quiet) { struct in_addr in; char buf[40]; in.s_addr = htonl(offer_addr); sprintf(buf, "%2.4g",_GMKv(filesize)); put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_REQUEST_FSET), "%s %s \"%s\" %s %s %s %d %s %s", update_clock(GET_TIME), dcc_name, description, nick, userhost, inet_ntoa(in), offer_port, _GMKs(filesize), buf)); } if (!filesize) put_it("%s", convert_output_format("$G %RDCC%n Warning: Offered file has zero size", NULL, NULL)); if (beep_on_level & LOG_DCC) beep_em(1); } static void dcc_chat_offer(char *nick, char *type, char *description, char *address, char *port, char *size, char *extra, char *userhost, int server) { int Ctype = DCC_CHAT; unsigned long filesize; unsigned long TempLong; unsigned int TempInt; DCC_int *n; int autoget = 0; if (!parse_offer_params(address, port, size, &TempLong, &TempInt, &filesize)) return; if (!check_collision(nick, description, Ctype)) return; n = create_dcc_int(nick, description, userhost, TempLong, TempInt, filesize, server); if (do_hook(DCC_REQUEST_LIST, "%s %s %s 0", nick, dcc_types[Ctype]->name, description)) { show_dcc_offer(nick, dcc_types[Ctype]->name, description, userhost, TempLong, TempInt); if (get_int_var(BOT_MODE_VAR) && n->ul) { autoget = 1; } else { extern char *last_chat_req; bitchsay("Type /chat to answer or /nochat to close"); malloc_strcpy(&last_chat_req, nick); } } n->dccnum = ++dcc_count; add_dcc_pending(n, Ctype|DCC_OFFER, process_dcc_chat); if (autoget) dcc_create(nick, n->filename, NULL, n->filesize, 0, Ctype, DCC_OFFER, process_dcc_chat); } #ifndef BITCHX_LITE static void dcc_bot_offer(char *nick, char *type, char *description, char *address, char *port, char *size, char *extra, char *userhost, int server) { int Ctype = DCC_BOTMODE; unsigned long filesize; unsigned long TempLong; unsigned int TempInt; DCC_int *n; if (!parse_offer_params(address, port, size, &TempLong, &TempInt, &filesize)) return; if (!check_collision(nick, description, Ctype)) return; n = create_dcc_int(nick, description, userhost, TempLong, TempInt, filesize, server); if (do_hook(DCC_REQUEST_LIST, "%s %s %s 0", nick, dcc_types[Ctype]->name, description)) { show_dcc_offer(nick, dcc_types[Ctype]->name, description, userhost, TempLong, TempInt); #if 0 if (p = get_string_var(BOT_PASSWORD_VAR)) { if (encrypt && !strcmp(p, encrypt)) ;/* do it */ message_from(NULL, LOG_CRAP); return; } #endif } n->dccnum = ++dcc_count; add_dcc_pending(n, Ctype|DCC_OFFER, process_dcc_bot); } #endif static int rename_file(char **new_file) { FILE *fp = NULL; char c[10]; char *tmp = NULL; char buffer[BIG_BUFFER_SIZE]; strlcpy(buffer, *new_file, sizeof buffer); do { if (fp != NULL) fclose(fp); sprintf(c, "%03i.", getrandom(0, 999)); tmp = dcc_fullname(c); malloc_strcat(&tmp, buffer); fp = fopen(tmp, "r"); new_free(&tmp); } while (fp != NULL); malloc_sprintf(new_file, "%s%s", c, buffer); return 0; } /* Logic to determine whether or not to autoget a file offer */ static int do_autoget(const char *nick, unsigned long filesize) { if (!get_int_var(DCC_AUTOGET_VAR) && !find_name_in_genericlist(nick, dcc_no_flood, DCC_HASHSIZE, 0)) return 0; if (filesize/1024 > get_int_var(DCC_MAX_AUTOGET_SIZE_VAR)) return 0; if (!filesize) return 0; return 1; } static void dcc_send_offer(char *nick, char *type, char *description, char *address, char *port, char *size, char *extra, char *userhost, int server) { int Ctype = DCC_FILEREAD; unsigned long filesize; unsigned long TempLong; unsigned int TempInt; unsigned long tdcc = 0; DCC_int *n; DCC_List *new_d; int autoget = 0; int autoresume = 0; struct stat resume_sb; char *fullname = NULL; if (!parse_offer_params(address, port, size, &TempLong, &TempInt, &filesize)) return; if (*type == 'T') tdcc = DCC_TDCC; if (!check_collision(nick, description, Ctype)) return; n = create_dcc_int(nick, description, userhost, TempLong, TempInt, filesize, server); if (do_hook(DCC_REQUEST_LIST,"%s %s %s %lu", nick, dcc_types[Ctype]->name, description, filesize)) { show_dcc_fileoffer(nick, dcc_types[Ctype]->name, description, userhost, TempLong, TempInt, filesize); } fullname = dcc_fullname(n->filename); autoget = do_autoget(nick, n->filesize); if (!dcc_overwrite_var && stat(fullname, &resume_sb) == 0) { /* File already exists */ if (autoget) { /* autoget of an existing file: either rename it, resume it, or punt */ if (get_int_var(DCC_AUTORENAME_VAR)) { rename_file(&n->filename); new_free(&fullname); fullname = dcc_fullname(n->filename); } #ifdef MIRC_BROKEN_DCC_RESUME else if (resume_sb.st_size < n->filesize && get_int_var(DCC_AUTORESUME_VAR)) { put_it("%s", convert_output_format("$G %RDCC%n Warning: File $0 exists: trying to autoresume", "%s", fullname)); autoresume = 1; } #endif else { autoget = 0; } } if (!autoget) { #ifdef MIRC_BROKEN_DCC_RESUME if (resume_sb.st_size < n->filesize) put_it("%s", convert_output_format("$G %RDCC%n Warning: File $0 exists: use /DCC RENAME or /DCC RESUME if you don't want to overwrite", "%s", fullname)); else #endif put_it("%s", convert_output_format("$G %RDCC%n Warning: File $0 exists: use /DCC RENAME if you don't want to overwrite", "%s", fullname)); } } n->dccnum = ++dcc_count; new_d = add_dcc_pending(n, Ctype|DCC_OFFER|tdcc, start_dcc_get); if (autoresume) { n->transfer_orders.byteoffset = resume_sb.st_size; n->bytes_read = 0L; new_d->sock.flags |= DCC_RESUME_REQ; send_ctcp(CTCP_PRIVMSG, nick, CTCP_DCC, "RESUME %s %d %ld", n->filename, n->remport, resume_sb.st_size); } if (autoget && fullname) { DCC_int *new = NULL; if (!dcc_quiet) { put_it("%s", convert_output_format("$G %RDCC%n Auto-accepting $0 of file %C$2-%n from %K[%C$1%K]", "%s%s %s %s", tdcc ? "T" : "", dcc_types[Ctype]->name, nick, n->filename)); } if ((n->file = open(fullname, O_WRONLY | O_CREAT | O_BINARY, 0644)) > 0) { if ((new = dcc_create(nick, n->filename, NULL, n->filesize, 0, Ctype, DCC_OFFER|tdcc, start_dcc_get))) new->blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); } else put_it("%s", convert_output_format("$G %RDCC%n Unable to open $0-", "%s", fullname)); } } static void dcc_resend_offer(char *nick, char *type, char *description, char *address, char *port, char *size, char *extra, char *userhost, int server) { int Ctype = DCC_REFILEREAD; unsigned long filesize; unsigned long TempLong; unsigned int TempInt; unsigned long tdcc = 0; DCC_int *n; int autoget = 0; char *fullname = NULL; if (!parse_offer_params(address, port, size, &TempLong, &TempInt, &filesize)) return; if (*type == 'T') tdcc = DCC_TDCC; if (!check_collision(nick, description, Ctype)) return; n = create_dcc_int(nick, description, userhost, TempLong, TempInt, filesize, server); if (do_hook(DCC_REQUEST_LIST,"%s %s %s %lu", nick, dcc_types[Ctype]->name, description, filesize)) { show_dcc_fileoffer(nick, dcc_types[Ctype]->name, description, userhost, TempLong, TempInt, filesize); } fullname = dcc_fullname(n->filename); autoget = do_autoget(nick, n->filesize); n->dccnum = ++dcc_count; add_dcc_pending(n, Ctype|DCC_OFFER|tdcc, start_dcc_get); if (autoget && fullname) { DCC_int *new = NULL; if (!dcc_quiet) { put_it("%s", convert_output_format("$G %RDCC%n Auto-accepting $0 of file %C$2-%n from %K[%C$1%K]", "%s%s %s %s", tdcc ? "T" : "", dcc_types[Ctype]->name, nick, n->filename)); } if ((n->file = open(fullname, O_WRONLY | O_CREAT | O_BINARY | O_APPEND, 0644)) > 0) { if ((new = dcc_create(nick, n->filename, NULL, n->filesize, 0, Ctype, DCC_OFFER|tdcc, start_dcc_get))) new->blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); } else put_it("%s", convert_output_format("$G %RDCC%n Unable to open $0-", "%s", fullname)); } } void handle_dcc_offer(char *nick, char *type, char *description, char *address, char *port, char *size, char *extra, char *userhost) { set_display_target(NULL, LOG_DCC); if (description) { char *c; #if defined(__EMX__) || defined(WINNT) if ((c = strrchr(description, '\\')) description = c + 1; #endif if ((c = strrchr(description, '/'))) description = c + 1; if (description && *description == '.') *description = '_'; } if (check_dcc_init(nick, type, description, address, port, size, extra, userhost)) { reset_display_target(); return; } if (!my_stricmp(type, "CHAT")) dcc_chat_offer(nick, type, description, address, port, size, extra, userhost, from_server); #ifndef BITCHX_LITE else if (!my_stricmp(type, "BOT")) dcc_bot_offer(nick, type, description, address, port, size, extra, userhost, from_server); #endif else if (!my_stricmp(type, "SEND") || !my_stricmp(type, "TSEND")) dcc_send_offer(nick, type, description, address, port, size, extra, userhost, from_server); else if (!my_stricmp(type, "RESEND") || !my_stricmp(type, "TRESEND")) dcc_resend_offer(nick, type, description, address, port, size, extra, userhost, from_server); #ifdef MIRC_BROKEN_DCC_RESUME else if (!my_stricmp(type, "RESUME")) /* * Dont be deceieved by the arguments we're passing it. * The arguments are "out of order" because MIRC doesnt * send them in the traditional order. Ugh. Comments * borrowed from epic. */ dcc_getfile_resume_demanded(nick, description, address, port); else if (!my_stricmp(type, "ACCEPT")) dcc_getfile_resume_start (nick, description, address, port); #endif else put_it("%s", convert_output_format("$G %RDCC%n Unknown DCC $0 ($1) received from $2", "%s %s %s", type, description, nick)); reset_display_target(); } void process_dcc(char *args) { char *command; int i; if (!(command = next_arg(args, &args))) return; reset_display_target(); if (dcc_dllcommands) { DCC_dllcommands *dcc_comm; if ((dcc_comm = (DCC_dllcommands *)find_in_list((List **)&dcc_dllcommands, command, 0))) { dcc_comm->function(dcc_comm->name, args); reset_display_target(); return; } } for (i = 0; dcc_commands[i].name != NULL; i++) { if (!my_strnicmp(dcc_commands[i].name, command, strlen(command))) { dcc_commands[i].function(dcc_commands[i].name, args); reset_display_target(); return; } } put_it("%s", convert_output_format("$G Unknown %RDCC%n command: $0", "%s", command)); reset_display_target(); } char *get_dcc_args(char **args, char **passwd, char **port, int *blocksize) { char *user = NULL; while (args && *args && **args) { char *argument = new_next_arg(*args, args); if (argument && *argument) { if (*argument == '-') { argument++; if (*argument == 'e') *passwd = next_arg(*args, args); else if (*argument == 'p') *port = next_arg(*args, args); else if (*argument == 'b') *blocksize = my_atol(next_arg(*args, args)); } else user = argument; } if (user) break; } return user; } void dcc_chat(char *command, char *args) { char *user; char *nick; char *passwd = NULL; char *port = NULL; char *equal_user = NULL; DCC_int *new = NULL; SocketList *s = NULL; int blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); int bot = 0; int flags = 0; #ifndef BITCHX_LITE if (command && !my_stricmp(command, "BOT")) bot++; #endif #ifdef HAVE_SSL if(my_strnicmp(args, "-SSL", 4) == 0) { new_next_arg(args, &args); flags = DCC_SSL; } #endif user = get_dcc_args(&args, &passwd, &port, &blocksize); if (!user) { put_it("%s", convert_output_format("$G %RDCC%n You must supply a nickname for DCC chat", NULL, NULL)); return; } if (!blocksize || blocksize > MAX_DCC_BLOCK_SIZE) blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); while ((nick = next_in_comma_list(user, &user))) { if (!nick || !*nick) break; if (isme(nick)) continue; if ((s = find_dcc(nick, "chat", NULL, bot?DCC_BOTMODE:DCC_CHAT, 1, -1, -1))) { if ((s->flags & DCC_ACTIVE) || (s->flags & DCC_WAIT)) put_it("%s", convert_output_format("$G %RDCC%n A previous DCC chat to $0 exists", "%s", nick)); new = (DCC_int *)s->info; if (s->flags & DCC_WAIT) { send_ctcp_booster(nick, dcc_types[DCC_CHAT]->name, "chat", htonl(get_int_var(DCC_USE_GATEWAY_ADDR_VAR) ? get_server_uh_addr(from_server).sf_addr.s_addr : get_server_local_addr(from_server).sf_addr.s_addr), htons(s->port), new->filesize); add_sockettimeout(s->is_read, 120, NULL); } continue; } if ((new = dcc_create(nick, "chat", passwd, 0, port? atol(port) : 0, bot?DCC_BOTMODE:DCC_CHAT, DCC_TWOCLIENTS|flags, start_dcc_chat))) { new->blocksize = blocksize; if (!bot) { equal_user = alloca(strlen(nick)+4); strcpy(equal_user, "="); strcat(equal_user, nick); addtabkey(equal_user, "msg", 0); } userhostbase(nick, add_userhost_to_chat, 1, NULL); } doing_multi++; } doing_multi = 0; } void close_dcc_file(int snum) { SocketList *s; DCC_int *n; char lame_ultrix[30]; /* should be plenty */ char lame_ultrix2[30]; char lame_ultrix3[30]; char *tofrom = NULL; char *filename, *p; #ifdef GUI char *who; #endif double xtime; double xfer; double temp; unsigned long type; char lame_type[30]; s = get_socket(snum); if (!s || !(n = (DCC_int *)s->info)) return; type = s->flags & DCC_TYPES; *lame_type = 0; if (s->flags & DCC_TDCC) strcpy(lame_type, "T"); strcat(lame_type, dcc_types[type]->name); xtime = time_since(&n->starttime); xfer = (double)(n->bytes_sent ? n->bytes_sent : n->bytes_read); if (xfer == 0.0) xfer = 1.0; if (xtime == 0.0) xtime = 1.0; temp = xfer / xtime; sprintf(lame_ultrix, "%2.4g %s", _GMKv(temp), _GMKs(temp)); /* Cant pass %g to put_it (lame ultrix/dgux), fix suggested by sheik. */ sprintf(lame_ultrix2, "%2.4g%s", _GMKv(xfer), _GMKs(xfer)); sprintf(lame_ultrix3, "%2.4g", xtime); filename = LOCAL_COPY(n->filename); p = filename; while ((p = strchr(p, ' '))) *p = '_'; switch(type) { case DCC_FILEREAD: case DCC_REFILEREAD: tofrom = "from"; break; case DCC_FILEOFFER: case DCC_REFILEOFFER: tofrom = "to"; break; default: tofrom = "to"; } set_display_target(NULL, LOG_DCC); if (do_hook(DCC_LOST_LIST, "%s %s %s %s TRANSFER COMPLETE", s->server, lame_type, strip_path(n->filename), lame_ultrix)) put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_LOST_FSET), "%s %s %s %s %s %s %s %s", update_clock(GET_TIME), lame_type, strip_path(filename), lame_ultrix2, tofrom, s->server, lame_ultrix3, lame_ultrix)); #ifdef GUI who = LOCAL_COPY(s->server); #endif erase_dcc_info(snum, 0, NULL); close_socketread(snum); update_transfer(); update_all_status(current_window, NULL, 0); #ifdef GUI gui_setfileinfo(filename, who, from_server); #endif reset_display_target(); } /* * following 3 functions process dcc filesends. */ void process_dcc_send1(int snum) { SocketList *s; DCC_int *n; u_32int_t bytes = 0; int bytesread = 0; char *buffer = alloca(MAX_DCC_BLOCK_SIZE+1); s = get_socket(snum); n = (DCC_int *)s->info; if (n->readwaiting || n->eof) { int numbytes = 0; if (!(s->flags & DCC_TDCC) && n->readwaiting) { if ((ioctl(snum, FIONREAD, &numbytes)) == -1) { erase_dcc_info(snum, 1, convert_output_format("$G %RDCC%n Remote $0 closed dcc send", "%s", s->server)); close_socketread(snum); return; } if (numbytes) { if (read(snum, &bytes, sizeof bytes) < (int)sizeof bytes) { erase_dcc_info(snum, 1, convert_output_format("$G %RDCC%n Remote closed dcc send", NULL)); close_socketread(snum); } bytes = (unsigned long)ntohl(bytes); get_time(&n->lasttime); if (bytes == (n->filesize - n->transfer_orders.byteoffset)) { close_dcc_file(snum); return; } else if (!n->dcc_fast && (bytes != n->bytes_sent)) return; n->readwaiting = 0; } } else if (n->eof) { u_32int_t *buf; n->readwaiting = 1; if ((ioctl(snum, FIONREAD, &numbytes) == -1)) { close_dcc_file(snum); return; } buf = alloca(numbytes+1); numbytes = read(snum, buf, numbytes); switch(numbytes) { case -1: erase_dcc_info(snum, 1, convert_output_format("$G %RDCC%n Remote $0 closed dcc send", "%s", s->server)); close_socketread(snum); break; case 0: close_dcc_file(snum); break; } return; } } if ((bytesread = read(n->file, buffer, n->blocksize)) > 0) { int num; my_encrypt(buffer, bytesread, n->encrypt); num = send(snum, buffer, bytesread, 0); if (num != bytesread) { if (num == -1) { if (errno == EWOULDBLOCK || errno == ENOBUFS) lseek(n->file, -bytesread, SEEK_CUR); else { erase_dcc_info(snum, 1, convert_output_format("$G %RDCC%n Remote $0 closed dcc send", "%s", s->server)); close_socketread(snum); return; } } else { lseek(n->file, -(bytesread - num), SEEK_CUR); n->bytes_sent += num; } n->readwaiting = 1; return; } n->bytes_sent += bytesread; n->packets = n->bytes_sent / n->blocksize; n->readwaiting = 1; get_time(&n->lasttime); if (!(n->packets % 10)) { update_transfer(); if (!(n->packets % 20)) update_all_status(current_window, NULL, 0); } } else if (!n->eof) { n->eof = 1; n->readwaiting = 1; } else if (!n->dcc_fast) close_dcc_file(snum); else n->readwaiting = 1; } void start_dcc_send(int s) { struct sockaddr_in remaddr; socklen_t sra; int type; int new_s = -1; int tdcc = 0; char *nick = NULL; unsigned long flags; DCC_int *n = NULL; struct transfer_struct received = {0}; char local_type[30]; if (!(flags = get_socketflags(s))) return; /* wrong place damn it */ nick = get_socketserver(s); sra = sizeof(struct sockaddr_in); new_s = my_accept(s, (struct sockaddr *) &remaddr, &sra); type = flags & DCC_TYPES; n = get_socketinfo(s); set_display_target(NULL, LOG_DCC); if ((add_socketread(new_s, ntohs(remaddr.sin_port), flags, nick, process_dcc_send1, NULL)) < 0) { erase_dcc_info(s, 1, "%s", convert_output_format("$G %RDCC error: accept() failed. punt!!", NULL, NULL)); close_socketread(s); return; } flags &= ~DCC_WAIT; flags |= DCC_ACTIVE; set_socketflags(new_s, flags); set_socketinfo(new_s, n); if ((n->file = open(n->filename, O_RDONLY | O_BINARY)) == -1) { erase_dcc_info(new_s, 1, "%s", convert_output_format("$G %RDCC%n Unable to open $0: $1-", "%s %s", n->filename, errno ? strerror(errno) : "Unknown Host")); close_socketread(new_s); close_socketread(s); return; } if (type == DCC_REFILEOFFER) { alarm(1); recv(new_s, (char *)&received, sizeof(struct transfer_struct), 0); alarm(0); if (byte_order_test() != received.byteorder) { /* the packet sender orders bytes differently than us, * reverse what they sent to get the right value */ n->transfer_orders.packet_id = ((received.packet_id & 0x00ff) << 8) | ((received.packet_id & 0xff00) >> 8); n->transfer_orders.byteoffset = ((received.byteoffset & 0xff000000) >> 24) | ((received.byteoffset & 0x00ff0000) >> 8) | ((received.byteoffset & 0x0000ff00) << 8) | ((received.byteoffset & 0x000000ff) << 24); } else memcpy(&n->transfer_orders,&received,sizeof(struct transfer_struct)); if (n->transfer_orders.packet_id != DCC_PACKETID) { put_it("%s", convert_output_format("$G %RDCC%n reget packet is invalid!!", NULL, NULL)); memset(&n->transfer_orders, 0, sizeof(struct transfer_struct)); } else put_it("%s", convert_output_format("$G %RDCC%n reget starting at $0", "%s", ulongcomma(n->transfer_orders.byteoffset))); } if (get_int_var(DCC_FAST_VAR) && !(flags & DCC_TDCC)) { set_non_blocking(new_s); n->dcc_fast = 1; } lseek(n->file, n->transfer_orders.byteoffset, SEEK_SET); errno = 0; *local_type = 0; if (tdcc) strcpy(local_type, "T"); strcat(local_type, dcc_types[type]->name); if (do_hook(DCC_CONNECT_LIST, "%s %s %s %d %ld %s", nick, local_type, inet_ntoa(remaddr.sin_addr), ntohs(remaddr.sin_port), (unsigned long)n->filesize, n->filename) && !dcc_quiet) put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_CONNECT_FSET), "%s %s %s %s %s %d %d", update_clock(GET_TIME), local_type, nick, n->userhost?n->userhost:"u@h", inet_ntoa(remaddr.sin_addr),ntohs(remaddr.sin_port),n->transfer_orders.byteoffset )); get_time(&n->starttime); get_time(&n->lasttime); close_socketread(s); process_dcc_send1(new_s); reset_display_target(); } void real_file_send(char *nick, char *filename, char *passwd, char *port, int tdcc, unsigned long type, int blocksize) { DCC_int *new = NULL; SocketList *s = NULL; unsigned long filesize = 0; char FileBuf[BIG_BUFFER_SIZE+1]; struct stat st; #if defined(__EMX__) || defined(WINNT) if (*filename == '/' || *filename == '\\') #else if (*filename == '/') #endif strncpy(FileBuf, filename, BIG_BUFFER_SIZE); else if (*filename == '~') { char *fullname; if (!(fullname = expand_twiddle(filename))) { put_it("%s", convert_output_format("$G %RDCC%n Unable to access $0", "%s", filename)); return; } strncpy(FileBuf, fullname, BIG_BUFFER_SIZE); new_free(&fullname); } #if defined(__EMX__) || defined(WINNT) else if (strlen(filename) > 3 && ( (*(filename+1) == ':') && (*(filename+2) == '/' || *(filename+2) == '\\')) ) strlcpy(FileBuf, filename, BIG_BUFFER_SIZE); #endif else { getcwd(FileBuf, BIG_BUFFER_SIZE); strlcat(FileBuf, "/", BIG_BUFFER_SIZE); strlcat(FileBuf, filename, BIG_BUFFER_SIZE); } #if defined(__EMX__) || defined(WINNT) convert_unix(FileBuf); #endif if (strchr(FileBuf , '*')) { char *path, *c, *filebuf = NULL; DIR *dp; struct dirent *dir; int count = 0; path = LOCAL_COPY(FileBuf); if ((c = strrchr(path, '/'))) *c++ = 0; if (!(dp = opendir(path))) return; while ((dir = readdir(dp))) { if (!dir->d_ino) continue; if (!wild_match(c, dir->d_name)) continue; malloc_sprintf(&filebuf, "%s/%s", path, dir->d_name); stat(filebuf, &st); if (S_ISDIR(st.st_mode)) { new_free(&filebuf); continue; } /* finally. do a send */ if ((s = find_dcc(nick, filebuf, NULL, type, 1, -1, -1))) { if ((s->flags & DCC_ACTIVE) || (s->flags & DCC_WAIT)) put_it("%s", convert_output_format("$G %RDCC%n A previous DCC send to $0 exists", "%s", nick)); new = (DCC_int *)s->info; if (s->flags & DCC_WAIT) { send_ctcp_booster(nick, dcc_types[type]->name, filebuf, htonl(get_server_local_addr(from_server).sf_addr.s_addr), htons(s->port), new->filesize); add_sockettimeout(s->is_read, 120, NULL); } continue; } if ((new = dcc_create(nick, filebuf, passwd, st.st_size, port? atol(port) : filesize, type, (tdcc? DCC_TDCC: 0) |DCC_TWOCLIENTS, start_dcc_send))) new->blocksize = blocksize; count++; new_free(&filebuf); } closedir(dp); if (!dcc_quiet) { char buff[30]; strcpy(buff, "file"); if (count > 1) strcat(buff, "s"); if (count) put_it("%s", convert_output_format("$G %RDCC%n Sent DCC SEND request to $0 for $1 $2-", "%s %s %s", nick, buff, filename)); else put_it("%s", convert_output_format("$G %RDCC%n No Files found matching $*", "%s", filename)); } return; } if (access(FileBuf, R_OK)) { put_it("%s", convert_output_format("$G %RDCC%n No such file $0 exists", "%s", FileBuf)); return; } stat(FileBuf, &st); if (S_ISDIR(st.st_mode)) { put_it("%s", convert_output_format("$G %RDCC%n $0 is a directory", "%s", FileBuf)); return; } if ((s = find_dcc(nick, FileBuf, NULL, type, 1, -1, -1))) { if ((s->flags & DCC_ACTIVE) || (s->flags & DCC_WAIT)) put_it("%s", convert_output_format("$G %RDCC%n A previous DCC send to $0 exists", "%s", nick)); new = (DCC_int *)s->info; if (s->flags & DCC_WAIT) { send_ctcp_booster(nick, dcc_types[type]->name, FileBuf, htonl(get_server_local_addr(from_server).sf_addr.s_addr), htons(s->port), new->filesize); add_sockettimeout(s->is_read, 120, NULL); } return; } if ((new = dcc_create(nick, FileBuf, passwd, st.st_size, port? atol(port) : filesize, type, (tdcc? DCC_TDCC: 0) |DCC_TWOCLIENTS, start_dcc_send))) new->blocksize = blocksize; } void BX_dcc_filesend(char *command, char *args) { char *user; char *nick; char *passwd = NULL; char *filename = NULL; char *port = NULL; int tdcc = 0; int blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); user = get_dcc_args(&args, &passwd, &port, &blocksize); if (!user) { put_it("%s", convert_output_format("$G %RDCC%n You must supply a nickname for DCC send", NULL, NULL)); return; } if (!blocksize || blocksize > MAX_DCC_BLOCK_SIZE) blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); if (command && *command == 'T') tdcc = DCC_TDCC; while ((nick = next_in_comma_list(user, &user))) { char *new_args; if (!nick || !*nick) break; new_args = LOCAL_COPY(args); while ((filename = new_next_arg(new_args, &new_args))) { if (!filename || !*filename) break; real_file_send(nick, filename, passwd, port, tdcc, DCC_FILEOFFER, blocksize); } doing_multi++; } doing_multi = 0; } void BX_dcc_resend(char *command, char *args) { char *user; char *nick; char *passwd = NULL; char *filename = NULL; char *port = NULL; int tdcc = 0; int blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); user = get_dcc_args(&args, &passwd, &port, &blocksize); if (!user) { put_it("%s", convert_output_format("$G %RDCC%n You must supply a nickname for DCC resend", NULL, NULL)); return; } if (!blocksize || blocksize > MAX_DCC_BLOCK_SIZE) blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); if (command && *command == 'T') tdcc = DCC_TDCC; while ((nick = next_in_comma_list(user, &user))) { char *new_args; if (!nick || !*nick) break; new_args = LOCAL_COPY(args); while ((filename = new_next_arg(new_args, &new_args))) { if (!filename || !*filename) break; real_file_send(nick, filename, passwd, port, tdcc, DCC_REFILEOFFER, blocksize); } doing_multi++; } doing_multi = 0; } void start_dcc_get(int snum) { SocketList *s = get_socket(snum); DCC_int *n = s->info; int bytes_read; char buffer[MAX_DCC_BLOCK_SIZE+1]; int err; set_display_target(NULL, LOG_DCC); bytes_read = read(snum, buffer, MAX_DCC_BLOCK_SIZE); switch(bytes_read) { case -1: erase_dcc_info(snum, 1, "%s", convert_output_format("$G %RDCC get to $0 lost: Remote peer closed connection", "%s", s->server)); close_socketread(snum); return; case 0: close_dcc_file(snum); return; } my_decrypt(buffer, bytes_read, n->encrypt); err = write(n->file, buffer, bytes_read); if (err == -1) { erase_dcc_info(snum, 1, "write to local file failed"); reset_display_target(); close_socketread(snum); return; } n->bytes_read += bytes_read; n->packets = n->bytes_read / n->blocksize; { u_32int_t bytes; bytes = htonl(n->bytes_read); send(snum, (char *)&bytes, sizeof(u_32int_t), 0); } if (n->filesize) { if (n->bytes_read + n->transfer_orders.byteoffset > n->filesize) { put_it("%s", convert_output_format("$G %RDCC%n Warning: incoming file is larger than the handshake said", NULL, NULL)); put_it("%s", convert_output_format("$G %RDCC%n Warning: GET: closing connection", NULL, NULL)); erase_dcc_info(snum, 1, NULL); close_socketread(snum); } else if ((n->bytes_read + n->transfer_orders.byteoffset) == n->filesize) { close_dcc_file(snum); reset_display_target(); return; } if (!(n->packets % 10)) { update_transfer(); if (!(n->packets % 20)) update_all_status(current_window, NULL, 0); } } reset_display_target(); } void real_get_file(char *user, char *filename, char *port, char *passwd, int tdcc, int blocksize) { DCC_int *new = NULL; SocketList *s = NULL; DCC_List *s1 = NULL; char *nick; while ((nick = next_in_comma_list(user, &user))) { if (!nick || !*nick) break; if ((s1 = find_dcc_pending(nick, filename, NULL, DCC_FILEREAD, 0, -1))) { new = (DCC_int *)s1->sock.info; if ((s = find_dcc(nick, new->filename, NULL, DCC_FILEREAD, 1, -1, -1))) { put_it("%s", convert_output_format("$G %RDCC%n A previous DCC GET from $0 exists", "%s", nick)); continue; } } else continue; if ((new = dcc_create(nick, filename, passwd, 0, port? atol(port) : 0, DCC_FILEREAD, (tdcc?DCC_TDCC:0) | DCC_TWOCLIENTS|DCC_OFFER, start_dcc_get))) { char *tmp = NULL; char *fullname = NULL; new->blocksize = blocksize; if (get_string_var(DCC_DLDIR_VAR)) malloc_sprintf(&tmp, "%s/%s", get_string_var(DCC_DLDIR_VAR), new->filename); else tmp = m_strdup(new->filename); if (!(fullname = expand_twiddle(tmp))) malloc_strcpy(&fullname, tmp); #if defined(WINNT) || defined(__EMX__) convert_unix(fullname); #endif s = find_dcc(nick, filename, NULL, DCC_FILEREAD, 1, -1, -1); if ((new->file = open(fullname, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0644)) == -1) { erase_dcc_info(s->is_read, 1, "%s", convert_output_format("$G %RDCC%n Unable to open $0: $1-", "%s %s", fullname, errno?strerror(errno):"Unknown")); close_socketread(s->is_read); } new_free(&fullname); new_free(&tmp); } doing_multi++; } } void dcc_getfile(char *command, char *args) { char *user; char *passwd = NULL; char *filename = NULL; char *port = NULL; int tdcc = 0; int blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); user = get_dcc_args(&args, &passwd, &port, &blocksize); if (!user) { put_it("%s", convert_output_format("$G %RDCC%n You must supply a nickname for DCC get", NULL, NULL)); return; } if (!blocksize || blocksize > MAX_DCC_BLOCK_SIZE) blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); if (command && *command == 'T') tdcc = 1; if (!args || !*args) real_get_file(user, NULL, port, passwd, tdcc, blocksize); else { char *u = alloca(strlen(user)+1); while ((filename = next_in_comma_list(args, &args))) { if (!filename || !*filename) break; strcpy(u, user); real_get_file(u, filename, port, passwd, tdcc, blocksize); } } doing_multi = 0; } void real_reget_file(char *user, char *filename, char *port, char *passwd, int tdcc, int blocksize) { DCC_int *new = NULL; SocketList *s = NULL; char *nick; while ((nick = next_in_comma_list(user, &user))) { char *tmp = NULL; char *fullname = NULL; DCC_List *s1 = NULL; if (!nick || !*nick) break; if ((s1 = find_dcc_pending(nick, filename, NULL, DCC_REFILEREAD, 0, -1))) { new = (DCC_int *)s1->sock.info; if ((s = find_dcc(nick, new->filename, NULL, DCC_REFILEREAD, 1, -1, -1))) { put_it("%s", convert_output_format("$G %RDCC%n A previous DCC REGET from $0 exists", "%s", nick)); continue; } } else continue; if (get_string_var(DCC_DLDIR_VAR)) malloc_sprintf(&tmp, "%s/%s", get_string_var(DCC_DLDIR_VAR), new->filename); else tmp = m_strdup(new->filename); if (!(fullname = expand_twiddle(tmp))) malloc_strcpy(&fullname, tmp); if ((new->file = open(fullname, O_WRONLY | O_CREAT | O_BINARY, 0644)) != -1) { if ((new = dcc_create(nick, new->filename, passwd, 0, port? atol(port) : 0, DCC_REFILEREAD, (tdcc?DCC_TDCC:0) | DCC_TWOCLIENTS|DCC_OFFER, start_dcc_get))) new->blocksize = blocksize; } new_free(&fullname); new_free(&tmp); doing_multi++; } } void dcc_regetfile(char *command, char *args) { char *user; char *passwd = NULL; char *filename = NULL; char *port = NULL; int tdcc = 0; int blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); user = get_dcc_args(&args, &passwd, &port, &blocksize); if (!user) { put_it("%s", convert_output_format("$G %RDCC%n You must supply a nickname for DCC reget", NULL, NULL)); return; } if (!blocksize || blocksize > MAX_DCC_BLOCK_SIZE) blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); if (command && *command == 'T') tdcc = 1; if (!args || !*args) real_reget_file(user, NULL, port, passwd, tdcc, blocksize); else { char *u = alloca(strlen(user)+1); while ((filename = next_in_comma_list(args, &args))) { if (!filename || !*filename) break; strcpy(u, user); real_reget_file(u, filename, port, passwd, tdcc, blocksize); } } doing_multi = 0; } static char *get_bar_percent(int percent) { #ifdef ONLY_STD_CHARS static char *_dcc_offer[12] = {"%K-.........%n", /* 0 */ "%K-.........%n", /* 10 */ "%K-=........%n", /* 20 */ "%K-=*.......%n", /* 30 */ "%K-=*%1%K=%0%K......%n", /* 40 */ "%K-=*%1%K=-%0%K.....%n", /* 50 */ "%K-=*%1%K=-.%0%K....%n", /* 60 */ "%K-=*%1%K=-. %0%K...%n", /* 70 */ "%K-=*%1%K=-. %R.%0%K..%n", /* 80 */ "%K-=*%1%K=-. %R.-%0%K.%n", /* 90 */ "%K-=*%1%K=-. %R.-=%n", /* 100 */ empty_string}; #else static char *_dcc_offer[12] = {"%K±°°°°°°°°°%n", /* 0 */ "%K±°°°°°°°°°%n", /* 10 */ "%K±²°°°°°°°°%n", /* 20 */ "%K±²Û°°°°°°°%n", /* 30 */ "%K±²Û%1%K²%0%K°°°°°°%n", /* 40 */ "%K±²Û%1%K²±%0%K°°°°°%n", /* 50 */ "%K±²Û%1%K²±°%0%K°°°°%n", /* 60 */ "%K±²Û%1%K²±°ÿ%0%K°°°%n", /* 70 */ "%K±²Û%1%K²±°ÿ%R°%0%K°°%n", /* 80 */ "%K±²Û%1%K²±°ÿ%R°±%0%K°%n", /* 90 */ "%K±²Û%1%K²±°ÿ%R°±²%n", /* 100 */ empty_string}; #endif if (percent <= 100) return _dcc_offer[percent]; return empty_string; } void dcc_glist(char *command, char *args) { char *dformat = "#$[3]0 $[6]1%Y$2%n $[11]3 $[25]4 $[7]5 $6-"; char *d1format = "#$[3]0 $[6]1%Y$2%n $[11]3 $4 $[7]5 $[11]6 $[7]7 $8-"; char *c1format = "#$[3]0 $[6]1%Y$2%n $[11]3 $4 $[-4]5 $[-4]6 $[-3]7 $[-3]8 $[7]9 $10"; int i; DCC_int *n = NULL; SocketList *s; int type; int tdcc = 0; char *status; int count = 0; DCC_List *c; char stats[80]; char kilobytes[20]; double barsize = 0.0; char spec[BIG_BUFFER_SIZE]; char *filename, *p; reset_display_target(); #if !defined(WINNT) && !defined(__EMX__) charset_ibmpc(); #endif if (do_hook(DCC_HEADER_LIST, "%s %s %s %s %s %s %s", "Dnum","Type","Nick", "Status", "K/s", "File","Encrypt")) { #ifdef ONLY_STD_CHARS put_it("%s", convert_output_format("%G# %W|%n %GT%gype %W|%n %GN%gick %W|%n %GP%gercent %GC%gomplete %W|%n %GK%g/s %W|%n %GF%gile", NULL, NULL)); put_it("%s", convert_output_format("%W------------------------------------------------------------------------------", NULL, NULL)); #else put_it("%s", convert_output_format("%G# %W³%n %GT%gype %W³%n %GN%gick %W³%n %GP%gercent %GC%gomplete %W³%n %GK%g/s %W³%n %GF%gile", NULL, NULL)); put_it("%s", convert_output_format("%KÄÄ%nÄ%WÄ%nÄ%KÄÄÄÄÄ%nÄ%WÄ%nÄ%KÄÄÄÄÄÄÄÄÄ%nÄ%WÄ%nÄ%KÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ%nÄ%WÄ%nÄ%KÄÄÄÄÄ%nÄ%WÄ%nÄ%KÄÄÄÄÄ%nÄ%WÄ%nÄ%KÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ", NULL, NULL)); #endif } for (c = pending_dcc; c; c = c->next, count++) { char local_type[30]; char *filename, *p; s = &c->sock; type = c->sock.flags & DCC_TYPES; tdcc = c->sock.flags & DCC_TDCC; n = (DCC_int *)c->sock.info; *local_type = 0; if (tdcc) strcpy(local_type, "T"); strcat(local_type, dcc_types[type]->name); filename = LOCAL_COPY(n->filename); p = filename; while ((p = strchr(p, ' '))) *p = '_'; if (do_hook(DCC_STAT_LIST, "%d %s %s %s %s %s %s", n->dccnum, local_type, c->sock.server, s->flags & DCC_OFFER ? "Offer" : s->flags & DCC_WAIT ? "Wait" : s->flags & DCC_ACTIVE ? "Active" : "Unknown", "N/A", strip_path(filename), n->encrypt?"E":empty_string)) { put_it("%s", convert_output_format(dformat, "%d %s %s %s %s %s %s", n->dccnum, local_type, n->encrypt ? "E" : "ÿ", c->sock.server, s->flags & DCC_OFFER ? "Offer " : s->flags & DCC_WAIT ? "Wait " : s->flags & DCC_ACTIVE ? "Active" : "Unknown", "N/A", strip_path(filename))); } count++; } for (i = 0; i < get_max_fd() + 1; i++, count++) { double perc = 0.0; double bytes = 0.0; char local_type[30]; time_t xtime; int seconds = 0, minutes = 0; int iperc = 0; int size = 0; if (!check_dcc_socket(i)) continue; s = get_socket(i); n = (DCC_int *)s->info; type = s->flags & DCC_TYPES; tdcc = s->flags & DCC_TDCC; xtime = now - n->starttime.tv_sec; if (xtime <= 0) xtime = 1; *local_type = 0; if (tdcc) strcpy(local_type, "T"); strcat(local_type, dcc_types[type]->name); filename = LOCAL_COPY(n->filename); p = filename; while ((p = strchr(p, ' '))) *p = '_'; if (((type == DCC_CHAT) || (type == DCC_RAW) || (type == DCC_BOTMODE) || (type == DCC_FTPOPEN))) { if (!(s->flags & DCC_ACTIVE)) xtime = now - s->time; if (do_hook(DCC_STAT_LIST, "%d %s %s %s %s %s %s", n->dccnum, local_type, s->server, s->flags & DCC_OFFER ? "Offer " : s->flags & DCC_WAIT ? "Wait " : s->flags & DCC_ACTIVE ?"Active" : "Unknown", "N/A", strip_path(filename), n->encrypt?"E":empty_string)) put_it("%s", convert_output_format(c1format, "%d %s %s %s %s %s %s %s", n->dccnum, local_type, n->encrypt ? "E" : "ÿ", s->server, s->flags & DCC_OFFER ? "Offer" : s->flags & DCC_WAIT ? "Wait" : s->flags & DCC_ACTIVE ? "Active" : "Unknown", convert_time(xtime), "N/A", strip_path(filename))); } else { if (!(s->flags & DCC_ACTIVE)) { if (do_hook(DCC_STAT_LIST, "%d %s %s %s %s %s %s", n->dccnum, local_type, s->server, s->flags & DCC_OFFER ? "Offer " : s->flags & DCC_WAIT ? "Wait " : s->flags & DCC_ACTIVE ?"Active" : "Unknown", "N/A", strip_path(filename), n->encrypt?"E":empty_string)) put_it("%s", convert_output_format(dformat, "%d %s %s %s %s %s %s", n->dccnum, local_type, n->encrypt ? "E" : "ÿ", s->server, s->flags & DCC_OFFER ? "Offer" : s->flags & DCC_WAIT ? "Wait" : s->flags & DCC_ACTIVE ? "Active" : "Unknown", "N/A", strip_path(filename))); continue; } bytes = n->bytes_read + n->bytes_sent; sprintf(kilobytes, "%2.4g", bytes / 1024.0 / xtime); type = s->flags & DCC_TYPES; tdcc = s->flags & DCC_TDCC; status = s->flags & DCC_OFFER ? "Offer":s->flags & DCC_ACTIVE ? "Active": s->flags&DCC_WAIT?"Wait":"Unknown"; if ((bytes >= 0) && (s->flags & DCC_ACTIVE)) { if (bytes && (n->filesize - n->transfer_orders.byteoffset) >= bytes) { perc = (100.0 * ((double)bytes + n->transfer_orders.byteoffset) / (double)(n->filesize)); if ( perc > 100.0) perc = 100.0; else if (perc < 0.0) perc = 0.0; seconds = (int) (( (n->filesize - n->transfer_orders.byteoffset - bytes) / (bytes / xtime)) + 0.5); minutes = seconds / 60; seconds = seconds - (minutes * 60); if (minutes > 999) { minutes = 999; seconds = 59; } if (seconds < 0) seconds = 0; } else seconds = minutes = perc = 0; iperc = ((int)perc) / 10; barsize = ((double) (n->filesize)) / (double) BAR_LENGTH; size = (int) ((double) bytes / (double)barsize); if (n->filesize == 0) size = BAR_LENGTH; sprintf(stats, "%4.1f", perc); if (!get_int_var(DCC_BAR_TYPE_VAR)) sprintf(spec, "%s %s%s %02d:%02d", get_bar_percent(iperc), stats, "%%", minutes, seconds); else sprintf(spec, "%s%s %02d:%02d", stats, "%%", minutes, seconds); strcpy(spec, convert_output_format(spec, NULL, NULL)); } if (do_hook(DCC_STATF_LIST, "%d %s %s %s %s %s %s", n->dccnum, local_type, s->server, status, kilobytes, strip_path(filename), n->encrypt?"E":empty_string)) { char *s1; if (!get_int_var(DCC_BAR_TYPE_VAR)) s1 = d1format; else s1 = dformat; put_it("%s", convert_output_format(s1, "%d %s %s %s %s %s %s", n->dccnum, local_type, n->encrypt ? "E":"ÿ", s->server, spec, kilobytes, strip_path(filename))); } /* This prints the second DCC stat line, if DCC_BAR_TYPE is non-zero. */ if (do_hook(DCC_STATF1_LIST, "%s %lu %lu %d %d", stats, (unsigned long)bytes, (unsigned long)n->filesize, minutes, seconds)) { char *stat_ptr, *spec_ptr; if (!get_int_var(DCC_BAR_TYPE_VAR)) continue; snprintf(stats, sizeof stats, "%4.1f%% (%lu of %lu bytes)", perc, (unsigned long)bytes, (unsigned long)n->filesize); snprintf(spec, sizeof spec, BOLD_TOG_STR "[" REV_TOG_STR "%*.*s" REV_TOG_STR "%*.*s]" BOLD_TOG_STR " ETA " BOLD_TOG_STR "%02d:%02d", size, size, space, BAR_LENGTH - size, BAR_LENGTH - size, space, minutes, seconds); spec_ptr = spec + 3 + (BAR_LENGTH - strlen(stats)) / 2; for (stat_ptr = stats; *stat_ptr && *spec_ptr; spec_ptr++) { if (*spec_ptr != REV_TOG && *spec_ptr != BOLD_TOG) *spec_ptr = *stat_ptr++; } put_it("%s", spec); } } } #if !defined(WINNT) && !defined(__EMX__) #if defined(LATIN1) charset_lat1(); #elif defined(CHARSET_CUSTOM) charset_cst(); #endif #endif if (!count) bitchsay("No active/pending dcc's"); else if (do_hook(DCC_POST_LIST, "%s %s %s %s %s %s %s", "DCCnum","Type","Nick", "Status", "K/s", "File","Encrypt")) ; } unsigned char byte_order_test(void) { unsigned short test = DCC_PACKETID; if (*((unsigned char *)&test) == ((DCC_PACKETID & 0xff00) >> 8)) return 0; if (*((unsigned char *)&test) == (DCC_PACKETID & 0x00ff)) return 1; return 0; } int BX_get_active_count(void) { int active = 0; register int i; register SocketList *s; register int type; for (i = 0; i < get_max_fd() + 1; i++) { if (check_dcc_socket(i)) { s = get_socket(i); type = s->flags & DCC_TYPES; if (type == DCC_REFILEREAD || type == DCC_FTPGET || type == DCC_FILEREAD || type == DCC_FILEOFFER || type == DCC_REFILEOFFER) active++; } } return active; } #if 0 void dcc_renumber_active(void) { register int i; SocketList *s; DCC_int *n; int j = 1; for (i = 0; i < get_max_fd() + 1; i++) { if (check_dcc_socket(i)) { s = get_socket(i); n = (DCC_int *)s->info; n->dccnum = j++; } } dcc_count = j; } #endif int check_dcc_list (char *name) { int do_it = 0; register int i = 0; for (i = 0; i < get_max_fd() + 1; i++) { if (check_dcc_socket(i)) { SocketList *s; s = get_socket(i); if (s->server && !my_stricmp(name, s->server) && !(s->flags & DCC_ACTIVE)) { switch (s->flags & DCC_TYPES) { case DCC_FILEOFFER: case DCC_FILEREAD: case DCC_REFILEOFFER: case DCC_REFILEREAD: do_it++; erase_dcc_info(i, 0, NULL); close_socketread(i); default: break; } } } } return do_it; } void update_transfer(void) { register unsigned count= 0; double perc = 0.0; register int i = 0; /* char temp_str[60];*/ double bytes; SocketList *s; DCC_int *n; unsigned long flags; char transfer_buffer[BIG_BUFFER_SIZE]; char *c; *transfer_buffer = 0; for (i = 0; i < get_max_fd() + 1 ; i++) { if (!check_dcc_socket(i)) continue; s = get_socket(i); flags = s->flags & DCC_TYPES; if ((s->flags & DCC_OFFER) || (s->flags & DCC_WAIT) || (flags == DCC_RAW) || (flags == DCC_RAW_LISTEN) || (flags == DCC_CHAT) || (flags == DCC_BOTMODE) || (flags == DCC_FTPOPEN)) continue; n = (DCC_int *)s->info; bytes = n->bytes_read + n->bytes_sent + n->transfer_orders.byteoffset; if (bytes >= 0) { if (n->filesize >= bytes && (n->filesize > 0)) { perc = (100.0 * ((double)bytes) / (double)(n->filesize)); if ( perc > 100.0) perc = 100.0; else if (perc < 0.0) perc = 0.0; } strmopencat(transfer_buffer, BIG_BUFFER_SIZE, ltoa((int)perc), "% ", NULL); #if 0 sprintf(temp_str,"%d%% ",(int) perc); strcat(transfer_buffer,temp_str); #endif } if (count++ > 9) break; } if (*(c = transfer_buffer)) chop(transfer_buffer, 1); do_hook(DCC_UPDATE_LIST, "%s", *c ? c : empty_string); if (*c) { while ((c = strchr(c, ' '))) *c = ','; } if (count) { /* chop(transfer_buffer, 1);*/ if (fget_string_var(FORMAT_DCC_FSET)) { strlcpy(DCC_current_transfer_buffer, convert_output_format(fget_string_var(FORMAT_DCC_FSET), "%s", transfer_buffer), sizeof DCC_current_transfer_buffer); chop(DCC_current_transfer_buffer, 4); } else snprintf(DCC_current_transfer_buffer, sizeof DCC_current_transfer_buffer, "[%s]", transfer_buffer); } else *DCC_current_transfer_buffer = 0; } /* * returns the string without the path (if present) Also * converts filename from " " to _ */ static char * strip_path(char *str) { char *ptr; #if 0 char *q; q = str; while ((q = strchr(q, ' '))) *q = '_'; #endif if (dcc_paths) return str; ptr = strrchr(str,'/'); if (ptr == NULL) return str; else return ptr+1; } void dcc_show_active(char *command, char * args) { put_it("%s", convert_output_format("$G %RDCC%n DCC Active = \002$0\002, Limit = \002$1\002", "%d %d", get_active_count(), get_int_var(DCC_SEND_LIMIT_VAR))); } void dcc_set_quiet(char *command, char *args ) { dcc_quiet ^=1; put_it("%s", convert_output_format("$G %RDCC%n DCC Quiet = \002$0\002", "%s", on_off(dcc_quiet))); } void dcc_set_paths(char *command, char *args) { dcc_paths ^= 1; put_it("%s", convert_output_format("$G %RDCC%n DCC paths is now \002$0\002", "%s", on_off(dcc_paths))); } void dcc_tog_rename(char *command, char *args) { int arename = get_int_var(DCC_AUTORENAME_VAR); arename ^= 1; set_int_var(DCC_AUTORENAME_VAR, arename); put_it("%s", convert_output_format("$G %RDCC%n DCC auto rename is now \002$0\002", "%s", on_off(get_int_var(DCC_AUTORENAME_VAR)))); } void dcc_tog_resume(char *command, char *args) { int arename = get_int_var(DCC_AUTORESUME_VAR); arename ^= 1; set_int_var(DCC_AUTORESUME_VAR, arename); put_it("%s", convert_output_format("$G %RDCC%n DCC auto resume is now \002$0\002", "%s", on_off(get_int_var(DCC_AUTORESUME_VAR)))); } void dcc_overwrite_toggle(char *command, char *args) { dcc_overwrite_var ^= 1; put_it("%s", convert_output_format(" DCC overwrite is now \002$0\002", "%s", on_off(dcc_overwrite_var))); } void dcc_tog_auto(char *command, char *args) { int dcc_auto = get_int_var(DCC_AUTOGET_VAR); dcc_auto ^= 1; set_int_var(DCC_AUTOGET_VAR, dcc_auto); put_it("%s", convert_output_format(" DCC autoget is now \002$0\002", "%s", on_off(dcc_auto))); } void dcc_stats (char *command, char *unused) { char max_rate_in[20]; char min_rate_in[20]; char max_rate_out[20]; char min_rate_out[20]; sprintf(max_rate_in, "%6.2f", dcc_max_rate_in/1024.0); sprintf(min_rate_in, "%6.2f", ((dcc_min_rate_in != DBL_MAX )?dcc_min_rate_in/1024.0: 0.0)); sprintf(max_rate_out, "%6.2f", dcc_max_rate_out/1024.0); sprintf(min_rate_out, "%6.2f", ((dcc_min_rate_out != DBL_MAX) ? dcc_min_rate_out/1024.0: 0.0)); if (do_hook(DCC_TRANSFER_STAT_LIST, "%lu %s %s %lu %s %s %lu %u %u %s %s %s %s", (unsigned long)dcc_bytes_in, max_rate_in, min_rate_in, (unsigned long)dcc_bytes_out, max_rate_out, min_rate_out, (unsigned long)(send_count_stat+get_count_stat), get_active_count(), get_int_var(DCC_SEND_LIMIT_VAR), on_off(get_int_var(DCC_AUTOGET_VAR)), on_off(dcc_paths), on_off(dcc_quiet), on_off(dcc_overwrite_var))) { char in[50], out[50]; sprintf(in, "%3.2f%s", _GMKv(dcc_bytes_in), _GMKs(dcc_bytes_in)); sprintf(out, "%3.2f%s", _GMKv(dcc_bytes_out), _GMKs(dcc_bytes_out)); #ifdef ONLY_CTD_CHARS put_it("%s",convert_output_format(" %G========================%K[%Cdcc transfer stats%K]%G=======================", NULL)); put_it("%s",convert_output_format(" %G| |", NULL)); put_it("%s",convert_output_format(" %G|%g|-%K[%Cx%cferd %Ci%cn%K]%g-|-%K[%Cx%cferd %Co%cut%K]%g-|-%K[%Ct%cotal %Cf%ciles%K]%g-|-%K[%Ca%cctive%K]%g-|-[%Cl%cimit%K]%g-|%G|", NULL)); put_it("%s",convert_output_format(" %G|%g| %W$[-10]0 %g| %W$[-10]1 %g| %W$[-10]2 %g| %W$[-8]3 %g| %W$[-7]4 %g|%G|", "%s %s %d %d %d", in, out,send_count_stat+get_count_stat,get_active_count(),get_int_var(DCC_SEND_LIMIT_VAR))); put_it("%s",convert_output_format(" %G|%g|------------|-------------|---------------|----------|---------|%G|", NULL)); put_it("%s",convert_output_format(" %G| |", NULL)); put_it("%s",convert_output_format(" %g|----%K[%Ci%cn %Cs%ctats%K]%g---|---%K[%Co%cut %Cs%ctats%K]%g---|----------%K[%Ct%coggles%K]%g----------|", NULL)); put_it("%s",convert_output_format(" %g| %Cm%nax: %W$[-6]0%n%Rkb/s %g| %Cm%nax: %W$[-6]1%n%Rkb/s %g| %Ca%nutoget: %W$[-3]2%n %Cp%naths: %W$[-3]3 %g|", "%s %s %s %s", max_rate_in, max_rate_out, on_off(get_int_var(DCC_AUTOGET_VAR)),on_off(dcc_paths))); put_it("%s",convert_output_format(" %g| %Cm%nin: %W$[-6]0%n%Rkb/s %g| %Cm%nin: %W$[-6]1%n%Rkb/s %g| %Co%nverwrite: %W$[-3]2%n %Cq%nuiet: %W$[-3]3 %g|", "%s %s %s %s", min_rate_in, min_rate_out, on_off(dcc_overwrite_var), on_off(dcc_quiet))); put_it("%s",convert_output_format(" %g|-----------------|-----------------|-----------------------------|", NULL)); #else put_it("%s",convert_output_format(" %GÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ%K[%Cdcc transfer stats%K]%GÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸", NULL)); put_it("%s",convert_output_format(" %G³ ³", NULL)); put_it("%s",convert_output_format(" %G³%gÖÄ%K[%Cx%cferd %Ci%cn%K]%gÄÖ-%K[%Cx%cferd %Co%cut%K]%gÄ·Ä%K[%Ct%cotal %Cf%ciles%K]%gÄÖÄ%K[%Ca%cctive%K]%gÄ·Ä[%Cl%cimit%K]%gÄ·%G³", NULL)); put_it("%s",convert_output_format(" %G³%gº %W$[-10]0 %gº %W$[-10]1 %gº %W$[-10]2 %gº %W$[-8]3 %gº %W$[-7]4 %gº%G³", "%s %s %d %d %d", in, out,send_count_stat+get_count_stat,get_active_count(),get_int_var(DCC_SEND_LIMIT_VAR))); put_it("%s",convert_output_format(" %G³%gÓÄÄÄÄÄÄÄÄÄÄÄĽÄÄÄÄÄÄÄÄÄÄÄÄÄÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽÄÄÄÄÄÄÄÄÄÄÓÄÄÄÄÄÄÄÄĽ%G³", NULL)); put_it("%s",convert_output_format(" %G³ ³", NULL)); put_it("%s",convert_output_format(" %gÖÄÄÄÄ%K[%Ci%cn %Cs%ctats%K]%gÄÄÄÖÄÄÄ%K[%Co%cut %Cs%ctats%K]%gÄÄÄ·ÄÄÄÄÄÄÄÄÄÄ%K[%Ct%coggles%K]%gÄÄÄÄÄÄÄÄÄÄ·", NULL)); put_it("%s",convert_output_format(" %gº %Cm%nax: %W$[-6]0%n%Rkb/s %gº %Cm%nax: %W$[-6]1%n%Rkb/s %gº %Ca%nutoget: %W$[-3]2%n %Cp%naths: %W$[-3]3 %gº", "%s %s %s %s", max_rate_in, max_rate_out, on_off(get_int_var(DCC_AUTOGET_VAR)),on_off(dcc_paths))); put_it("%s",convert_output_format(" %gº %Cm%nin: %W$[-6]0%n%Rkb/s %gº %Cm%nin: %W$[-6]1%n%Rkb/s %gº %Co%nverwrite: %W$[-3]2%n %Cq%nuiet: %W$[-3]3 %gº", "%s %s %s %s", min_rate_in, min_rate_out, on_off(dcc_overwrite_var), on_off(dcc_quiet))); put_it("%s",convert_output_format(" %gÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ", NULL)); #endif } } /* * only call this on dcc finish */ void dcc_update_stats (int snum) { time_t xtime; SocketList *s; DCC_int *n; s = get_socket(snum); if (!s || !(n = (DCC_int *)s->info)) return; dcc_bytes_in += n->bytes_read; dcc_bytes_out += n->bytes_sent; xtime = time_since(&n->starttime); if (xtime <= 0) xtime = 1; if (n->bytes_read) { get_count_stat++; if ((double)n->bytes_read/(double)xtime > dcc_max_rate_in) dcc_max_rate_in = (double)n->bytes_read/(double)xtime; if ((double)n->bytes_read/ (double)xtime < dcc_min_rate_in) dcc_min_rate_in = (double)n->bytes_read/(double)xtime; } if (n->bytes_sent) { send_count_stat++; if ((double)n->bytes_sent/(double)xtime > dcc_max_rate_out) dcc_max_rate_out = (double)n->bytes_sent/(double)xtime; if ((double)n->bytes_sent/(double)xtime < dcc_min_rate_out) dcc_min_rate_out = (double)n->bytes_sent/ (double)xtime; } } /* Looks for the dcc transfer that is "current" (last received data) * and returns information for it */ extern char *DCC_get_current_transfer (void) { return DCC_current_transfer_buffer; } BUILT_IN_COMMAND(chat) { int no_chat = 0, flags = 0; if (!my_strnicmp(command, "NOC", 3)) no_chat = 1; #if HAVE_SSL if(my_strnicmp(args, "-SSL", 4) == 0) { new_next_arg(args, &args); flags = DCC_SSL; } #endif if (args && *args) { char *tmp = NULL; if (no_chat) malloc_sprintf(&tmp, "CLOSE CHAT %s", args); else #ifdef HAVE_SSL if(flags & DCC_SSL) malloc_sprintf(&tmp, "CHAT -ssl %s", args); else #endif malloc_sprintf(&tmp, "CHAT %s", args); process_dcc(tmp); new_free(&tmp); } else if (last_chat_req) { DCC_int *new; if (no_chat) { char *tmp = NULL; malloc_sprintf(&tmp, "CLOSE CHAT %s", last_chat_req); process_dcc(tmp); new_free(&tmp); } if ((new = dcc_create(last_chat_req, "chat", NULL, 0, 0, DCC_CHAT, DCC_TWOCLIENTS|DCC_OFFER|flags, start_dcc_chat))) { char *equal_user; new->blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); equal_user = alloca(strlen(last_chat_req)+4); strcpy(equal_user, "="); strcat(equal_user, last_chat_req); addtabkey(equal_user, "msg", 0); userhostbase(last_chat_req, add_userhost_to_chat, 1, NULL); new_free(&last_chat_req); } } } void dcc_exempt(char *command, char *args) { int remove; List *nptr = NULL; char *nick; if (!args || !*args) { int count = 0; for (nptr = next_namelist(dcc_no_flood, NULL, DCC_HASHSIZE); nptr; nptr = next_namelist(dcc_no_flood, nptr, DCC_HASHSIZE)) { if (count == 0) put_it("%s", convert_output_format("$G %RDCC%n autoget list/no flood list", NULL, NULL)); put_it("%s", nptr->name); count++; } if (count == 0) userage("dcc exempt", "+nick to add, nick to remove"); return; } nick = next_arg(args, &args); while (nick && *nick) { remove = 1; if (*nick == '+') { remove = 0; nick++; } nptr = find_name_in_genericlist(nick, dcc_no_flood, DCC_HASHSIZE, remove); if (remove && nptr) { bitchsay("removed %s from dcc exempt list", nick); new_free(&nptr->name); new_free((char **)&nptr); } else if (!remove && !nptr) { add_name_to_genericlist(nick, dcc_no_flood, DCC_HASHSIZE); bitchsay("added %s to dcc exempt list", nick); } else if (remove && !nptr) put_it("%s", convert_output_format("$G %RDCC%n No such nick on the exempt list %K[%W$0%K]", "%s", nick)); nick = next_arg(args, &args); } } int dcc_exempt_save(FILE *fptr) { int count = 0; List *nptr = NULL; fprintf(fptr, "# Exemptions from DCC autoget / flooding controls\n"); for (nptr = next_namelist(dcc_no_flood, NULL, DCC_HASHSIZE); nptr; nptr = next_namelist(dcc_no_flood, nptr, DCC_HASHSIZE)) { fprintf(fptr, "DCC EXEMPT +%s\n", nptr->name); count++; } if (count && do_hook(SAVEFILE_LIST, "DCCexempt %d", count)) bitchsay("Saved %d DccExempt entries", count); return count; } /* * This is a callback. When we want to do a CTCP DCC REJECT, we do * a WHOIS to make sure theyre still on irc, no sense sending it to * nobody in particular. When this gets called back, that means the * peer is indeed on irc, so we send them the REJECT. */ static void output_reject_ctcp (UserhostItem *stuff, char *nick, char *args) { char *nickname_received; char *type; char *description; if (!strcmp(stuff->user, "")) return; /* * XXX This is, of course, a monsterous hack. */ next_arg(args, &args); type = next_arg(args, &args); description = next_arg(args, &args); nickname_received = stuff->nick; if (nickname_received && *nickname_received) send_ctcp(CTCP_NOTICE, nickname_received, CTCP_DCC, "REJECT %s %s", type, description); } extern void dcc_reject (char *from, char *type, char *args) { SocketList *s; DCC_List *s1 = NULL; char *description; int CType; int tdcc = 0; upper(type); if (*type == 'T' && *(type+1)) tdcc = 1; for (CType = 0; dcc_types[CType]->name != NULL; CType++) if (!strcmp(type+tdcc, dcc_types[CType]->name)) break; if (!dcc_types[CType]->name) return; if (tdcc) CType |= DCC_TDCC; description = next_arg(args, &args); if ((s = find_dcc(from, description, NULL, CType, 0, -1, -1)) || (s1 = find_dcc_pending(from, description, NULL, CType, 1, -1))) { DCC_int *n; if (s1) s = & s1->sock; n = (DCC_int *)s->info; if (do_hook(DCC_LOST_LIST,"%s %s %s REJECTED", from, type, description ? description : "")) put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_ERROR_FSET), "%s %s %s %s", update_clock(GET_TIME), type, s->server, n->filename)); if (!s1) erase_dcc_info(s->is_read, 0, NULL); close_socketread(s->is_read); if (s1) { new_free(&s->server); new_free(&n->userhost); new_free(&n->user); new_free(&n->encrypt); new_free(&n->filename); new_free(&s1); } #ifdef WANT_CDCC dcc_sendfrom_queue(); #endif update_transfer(); update_all_status(current_window, NULL, 0); } } BUILT_IN_COMMAND(dcx) { int i; unsigned long flag; SocketList *s; int all = 0; unsigned long type = 0; char *nick = NULL; if (!my_stricmp(command, "DCA")) all = 1; else if (!my_stricmp(command, "DCG")) type = DCC_FILEREAD; else if (!my_stricmp(command, "DCS")) type = DCC_FILEOFFER; else if (!my_stricmp(command, "DCX")) type = DCC_CHAT; else return; nick = next_arg(args, &args); if (!all && !nick) return; for (i = 0; i < get_max_fd() + 1; i++) { if (!check_dcc_socket(i)) continue; s = get_socket(i); flag = s->flags & DCC_TYPES; if (all || (type == flag)) { if ((!all && nick) || (all && nick)) { if (!wild_match(nick, s->server)) continue; } erase_dcc_info(i, 1, "%s", convert_output_format("$G %RDCC%n closing dcc $0 to $1", "%s %s", dcc_types[flag]->name, s->server)); close_socketread(i); } } return; } void close_all_dcc(void) { int i; SocketList *s; unsigned long flag; for (i = 0; i < get_max_fd() + 1; i++) { if (!check_dcc_socket(i)) continue; s = get_socket(i); flag = s->flags & DCC_TYPES; erase_dcc_info(i, 1, "%s", convert_output_format("$G %RDCC%n closing dcc $0 to $1", "%s %s", dcc_types[flag]->name, s->server)); close_socketread(i); } return; } static char *last_notify = NULL; void cancel_dcc_auto(int i, unsigned long flags, SocketList *s) { if (!last_notify || strcmp(s->server,last_notify)) { send_to_server("NOTICE %s :DCC %s Auto Closed", s->server, dcc_types[flags]->name); malloc_strcpy(&last_notify, s->server); } erase_dcc_info(i, 1, "%s", convert_output_format("$G %RDCC%n Auto-closing idle dcc $0 to $1", "%s %s", dcc_types[flags]->name, s->server)); close_socketread(i); } void dcc_check_idle(void) { int i; time_t dcc_idle_time = get_int_var(_CDCC_CLOSE_IDLE_SENDS_TIME_VAR); #ifdef WANT_CDCC int minidlecheck = get_int_var(_CDCC_MINSPEED_TIME_VAR); #endif SocketList *s = NULL; DCC_int *n = NULL; unsigned long flags; if (pending_dcc) { DCC_List *s1 = pending_dcc, *last = NULL; while (s1) { s = &s1->sock; n = (DCC_int *)s->info; if (now >= s->time) { if (last) last->next = s1->next; else pending_dcc = s1->next; new_free(&s->server); new_free(&n->user); new_free(&n->filename); new_free(&n->userhost); new_free(&n->encrypt); close_socketread(s->is_read); new_free(&n); new_free(&s1); break; } last = s1; s1 = s1->next; } } for (i = 0; i < get_max_fd()+1; i++) { time_t client_idle, this_idle_time; if (!check_dcc_socket(i)) continue; s = get_socket(i); n = (DCC_int *)s->info; flags = s->flags & DCC_TYPES; client_idle = now - n->lasttime.tv_sec; switch (flags) { case DCC_FILEOFFER: case DCC_FILEREAD: case DCC_REFILEOFFER: case DCC_REFILEREAD: this_idle_time = dcc_idle_time * 3; break; default: this_idle_time = dcc_timeout; break; } if (!(s->flags & DCC_ACTIVE)) { if ((client_idle > this_idle_time)) cancel_dcc_auto(i, flags, s); continue; } #ifdef WANT_CDCC switch (flags) { case DCC_FILEOFFER: case DCC_REFILEOFFER: if (cdcc_minspeed && minidlecheck && (((now - n->starttime.tv_sec) % minidlecheck) == 0)) { unsigned long sent = n->bytes_sent / 1024; double this_speed = 0.0; char lame_ultrix1[20]; char lame_ultrix[20]; this_speed = (double)((double) sent / (double)(now- n->starttime.tv_sec)); if (this_speed < (float)cdcc_minspeed) { sprintf(lame_ultrix, "%2.4g", (double)(sent / (now - n->starttime.tv_sec))); sprintf(lame_ultrix1,"%2.4g", (double)cdcc_minspeed); if (!last_notify || strcmp(s->server,last_notify)) { send_to_server("NOTICE %s :CDCC Slow dcc %s Auto Closed. Require %sKB/s got %sKB/s", s->server, dcc_types[flags]->name, lame_ultrix1, lame_ultrix); malloc_strcpy(&last_notify, s->server); } erase_dcc_info(i, 1, "%s", convert_output_format("$G %RDCC%n Auto-closing Slow dcc $0 to $1 require $2KB/s got $3KB/s", "%s %s %s %s", dcc_types[flags]->name, s->server, lame_ultrix1, lame_ultrix)); close_socketread(i); } break; } if (client_idle > this_idle_time) cancel_dcc_auto(i, flags, s); default: break; } #endif } #ifdef WANT_CDCC cdcc_timer_offer(); #endif return; } void dcc_close(char *command, char *args) { char *type; char *file; char *nick; int any_type = 0; int any_user = 0; int count = 0; SocketList *s; DCC_List *s1; int i; int num = -1; type = next_arg(args, &args); nick = next_arg(args, &args); file = next_arg(args, &args); if (type) { if (!my_stricmp(type, "-all") || !strcmp(type, "*")) any_type = 1; else if (*type == '#' && (num = my_atol(type+1))) any_type = 1; } if (nick && (!my_stricmp(nick, "-all") || !strcmp(nick, "*"))) any_user = 1; if (!type || (!nick && (!any_type || num == -1))) { bitchsay("Specify a nick and a type to close or a number"); return; } if (!any_type) { for (i = 0; dcc_types[i]->name; i++) if (!my_stricmp(dcc_types[i]->name, type)) break; if (!dcc_types[i]->name) { bitchsay("Unknown dcc type for close"); return; } } else i = -1; if (any_user) nick = NULL; while ((s = find_dcc(nick, file, NULL, i, 0, -1, num))) { DCC_int *n; n = (DCC_int *)s->info; count++; if (do_hook(DCC_LOST_LIST,"%s %s %s USER ABORTED CONNECTION", s->server, dcc_types[s->flags & DCC_TYPES]->name, n->filename ? n->filename : "")) say("DCC %s:%s to %s closed", dcc_types[s->flags & DCC_TYPES]->name, file ? file : "", s->server); erase_dcc_info(s->is_read, 1, NULL); close_socketread(s->is_read); } while ((s1 = find_dcc_pending(nick, file, NULL, i, 1, num))) { DCC_int *n; s = &s1->sock; n = (DCC_int *)s->info; count++; if (do_hook(DCC_LOST_LIST,"%s %s %s USER ABORTED CONNECTION", s->server, dcc_types[s->flags & DCC_TYPES]->name, n->filename ? n->filename : "")) say("DCC %s:%s to %s closed", dcc_types[s->flags & DCC_TYPES]->name, file ? file : "", s->server); send_reject_ctcp(s->server, (((s->flags & DCC_TYPES) == DCC_FILEOFFER) ? "GET" : ((s->flags & DCC_TYPES) == DCC_FILEREAD) ? "SEND" : dcc_types[s->flags & DCC_TYPES]->name), n->filename); new_free(&s->server); new_free(&n->user); new_free(&n->filename); new_free(&n->userhost); new_free(&n->encrypt); close_socketread(s->is_read); new_free(&n); new_free(&s1); } if (!count) put_it("%s", convert_output_format("$G %RDCC%n No DCC $0:$1 to $2 found", "%s %s %s", (i == -1 ? "" : type), (file ? file : ""), (num != -1) ? ltoa(num): nick ? nick : "(null)")); update_transfer(); return; } void dcc_closeall(char *command, char *args) { close_all_dcc(); } extern int doing_notice; #ifdef MIRC_BROKEN_DCC_RESUME void dcc_getfile_resume_demanded(char *nick, char *filename, char *port, char *offset) { SocketList *s; DCC_int *n; int old_dp, old_dn, old_dc; if (filename && !strcmp(filename, "file.ext")) filename = NULL; if (!(s = find_dcc(nick, filename, port, DCC_FILEOFFER, 1, -1, -1))) { put_it("%s", convert_output_format("$G %RDCC%n warning in dcc_getfile_resume_demanded", NULL)); return; } n = (DCC_int *)s->info; if (!offset) return; old_dp = doing_privmsg; old_dn = doing_notice; old_dc = in_ctcp_flag; n->bytes_read = n->transfer_orders.byteoffset = my_atol(offset); /* n->bytes_read = 0L;*/ doing_privmsg = doing_notice = in_ctcp_flag = 0; send_ctcp(CTCP_PRIVMSG, nick, CTCP_DCC, "ACCEPT %s %s %s", filename, port, offset); doing_privmsg = old_dp; doing_notice = old_dn; in_ctcp_flag = old_dc; } void dcc_getfile_resume_start(char *nick, char *description, char *port, char *offset) { SocketList *s; DCC_int *n; const DCC_List *pending; char *tmp = NULL; char *fullname = NULL; struct stat sb; /* resume command has been sent and accepted. */ if (description && !strcmp(description, "file.ext")) description = NULL; if ((s = find_dcc(nick, description, NULL, DCC_FILEREAD, 1, 1, -1))) { put_it("%s", convert_output_format("$G %RDCC%n warning in dcc_getfile_resume_start", NULL)); return; } pending = find_dcc_pending(nick, description, NULL, DCC_FILEREAD, 0, -1); if (!pending || !(pending->sock.flags & DCC_RESUME_REQ)) { put_it("%s", convert_output_format("$G %RDCC%n Ignoring unsolicited ACCEPT from $0", "%s", nick)); return; } if (!(n = dcc_create(nick, description, NULL, 0, port?atol(port):0, DCC_FILEREAD, DCC_TWOCLIENTS|DCC_OFFER, start_dcc_get))) return; if (get_string_var(DCC_DLDIR_VAR)) malloc_sprintf(&tmp, "%s/%s", get_string_var(DCC_DLDIR_VAR), n->filename); else tmp = m_strdup(n->filename); if (!(fullname = expand_twiddle(tmp))) malloc_strcpy(&fullname, tmp); if ( !(n->file = open(fullname, O_WRONLY | O_APPEND | O_BINARY, 0644)) || (fstat(n->file, &sb) != 0) || (sb.st_size >= n->filesize) ) { int snum; if ((s = find_dcc(nick, description, NULL, DCC_FILEREAD, 0, 1, -1))) n = (DCC_int *)s->info; if (s) { snum = s->is_read; erase_dcc_info(snum, 1, "%s", convert_output_format("$G %RDCC%n Unable to open $0: $1-", "%s %s", n->filename, errno?strerror(errno):"incoming file smaller than existing")); close_socketread(snum); } } else put_it("%s", convert_output_format("$G %RDCC%n RESUME of $0 at $1", "%s %l", n->filename, sb.st_size)); new_free(&fullname); new_free(&tmp); } void dcc_resume(char *command, char *args) { char *user, *nick; char *filename = NULL; char *fullname = NULL; char *tmp = NULL; char *passwd = NULL; char *port = NULL; struct stat sb; int old_dp, old_dn, old_dc; int blocksize = 0; user = get_dcc_args(&args, &passwd, &port, &blocksize); if (!user) { put_it("%s", convert_output_format("$G %RDCC%n You must supply a nickname for DCC RESUME", NULL)); return; } if (!blocksize || blocksize > MAX_DCC_BLOCK_SIZE) blocksize = get_int_var(DCC_BLOCK_SIZE_VAR); if (args && *args) filename = args; tmp = NULL; while ((nick = next_in_comma_list(user, &user))) { SocketList *s; DCC_int *n; DCC_List *s1 = NULL; if (!nick || !*nick) break; if ((s = find_dcc(nick, filename, NULL, DCC_FILEREAD, 1, 1, -1))) { put_it("%s", convert_output_format("$G %RDCC%n DCC send already active. Unable to RESUME", NULL)); continue; } for (s1 = pending_dcc; s1; s1 = s1->next) { if (my_stricmp(s1->nick, nick)) continue; if ( ((s1->sock.flags & DCC_TYPES) != DCC_FILEREAD) || (s1->sock.flags & DCC_ACTIVE)) continue; break; } if (!s1) continue; s = &s1->sock; n = (DCC_int *)s->info; if (get_string_var(DCC_DLDIR_VAR)) malloc_sprintf(&tmp, "%s/%s", get_string_var(DCC_DLDIR_VAR), n->filename); else tmp = m_strdup(n->filename); if (!(fullname = expand_twiddle(tmp))) malloc_strcpy(&fullname, tmp); /* * This has to be done by hand, we cant use send_ctcp, * because this violates the protocol, and send_ctcp checks * for that. Ugh. */ if (stat(fullname, &sb) == -1) { /* File doesnt exist. Sheesh. */ put_it("%s", convert_output_format("$G %RDCC%n Cannot use DCC RESUME if the file doesn't exist [$0|$1-]", "%s %s", fullname, strerror(errno))); continue; } if (passwd) n->encrypt = m_strdup(passwd); n->bytes_sent = 0L; n->blocksize = blocksize; n->transfer_orders.byteoffset = sb.st_size; s->flags |= DCC_RESUME_REQ; old_dp = doing_privmsg; old_dn = doing_notice; old_dc = in_ctcp_flag; /* Just in case we have to fool the protocol enforcement. */ doing_privmsg = doing_notice = in_ctcp_flag = 0; send_ctcp(CTCP_PRIVMSG, nick, CTCP_DCC, "RESUME %s %d %ld", n->filename, n->remport, sb.st_size); doing_privmsg = old_dp; doing_notice = old_dn; in_ctcp_flag = old_dc; } new_free(&tmp); new_free(&fullname); /* Then we just sit back and wait for the reply. */ } #endif void dcc_help1(char *command, char *args) { char *comm; int i, c; char buffer[BIG_BUFFER_SIZE+1]; DCC_dllcommands *dcc_comm = NULL; if (args && *args) { comm = next_arg(args, &args); upper(comm); if ((dcc_comm = (DCC_dllcommands *)find_in_list((List **)&dcc_dllcommands, comm, 0))) { put_it("%s", convert_output_format("$G Usage: %W/%R$0%n $1 %K-%n $2-", "DCC %s %s", dcc_comm->name, dcc_comm->help?dcc_comm->help:"No help availble yet")); return; } for (i = 0; dcc_commands[i].name != NULL; i++) { if (!strncmp(comm, dcc_commands[i].name, strlen(comm))) { put_it("%s", convert_output_format("$G Usage: %W/%R$0%n $1 %K-%n $2-", "DCC %s %s", dcc_commands[i].name, dcc_commands[i].help?dcc_commands[i].help:"No help availble yet")); return; } } } put_it("%s", convert_output_format("$G %RDCC%n help -", NULL, NULL)); *buffer = 0; c = 0; for (dcc_comm = dcc_dllcommands; dcc_comm; dcc_comm = dcc_comm->next) { strcat(buffer, dcc_comm->name); strcat(buffer, space); if (++c == 5) { put_it("%s", convert_output_format("$G $[13]0 $[13]1 $[13]2 $[13]3 $[13]4", "%s", buffer)); *buffer = 0; c = 0; } } if (c) put_it("%s", convert_output_format("$G $[13]0 $[13]1 $[13]2 $[13]3 $[13]4", "%s", buffer)); *buffer = 0; c = 0; for (i = 0; dcc_commands[i].name; i++) { strcat(buffer, dcc_commands[i].name); strcat(buffer, space); if (++c == 5) { put_it("%s", convert_output_format("$G $[13]0 $[13]1 $[13]2 $[13]3 $[13]4", "%s", buffer)); *buffer = 0; c = 0; } } if (c) put_it("%s", convert_output_format("$G $[13]0 $[13]1 $[13]2 $[13]3 $[13]4", "%s", buffer)); userage("dcc help", "[command] to get help on specific commands"); } void read_ftp_file(int snum) { int len = 0; char *buf; SocketList *s; DCC_int *n; int err; if ((ioctl(snum, FIONREAD, &len) == -1)) { put_it("%s", convert_output_format("$G %gFTP%n file error [$0-]", "%s", strerror(errno))); erase_dcc_info(snum, 0, NULL); close_socketread(snum); return; } s = get_socket(snum); n = (DCC_int *)s->info; buf = alloca(len+1); err = read(snum, buf, len); switch(err) { case -1: erase_dcc_info(snum, 0, NULL); close_socketread(snum); break; case 0: close_dcc_file(snum); break; default: write(n->file, buf, len); n->bytes_read += len; n->packets++; get_time(&n->lasttime); } } int open_listen_port(int s) { struct sockaddr_in data_addr = { 0 }; socklen_t len = sizeof(struct sockaddr_in); int data_s; const int on = 1; unsigned char *a, *p; if (getsockname(s, (struct sockaddr *)&data_addr, &len) < 0) return -1; data_addr.sin_port = 0; if ((data_s = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1; if ((setsockopt(data_s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) { close(data_s); return -1; } if ((bind(data_s, (struct sockaddr *)&data_addr, sizeof(data_addr))) < 0) { close(data_s); return -1; } if ((listen(data_s, 1)) < 0) { close(data_s); return -1; } len = sizeof(struct sockaddr_in); getsockname(data_s, (struct sockaddr *)&data_addr, &len); a = (unsigned char *)&data_addr.sin_addr; p = (unsigned char *)&data_addr.sin_port; dcc_printf(s, "PORT %d,%d,%d,%d,%d,%d\n", a[0], a[1], a[2], a[3], p[0], p[1]); return data_s; } int handle_ftp(int comm, int snum, SocketList *s, char *buf) { int err = 0; DCC_int *n; n = (DCC_int *)s->info; get_time(&n->lasttime); switch(comm) { case 220: if (n->userhost) err = dcc_printf(snum, "user %s\r\n", n->userhost); new_free(&n->userhost); break; case 226: s->flags &= ~DCC_WAIT; return 0; case 331: if (n->encrypt) { err = dcc_printf(snum, "pass %s\r\n", n->encrypt); if (err != -1) err = dcc_printf(snum, "type I\r\n"); } new_free(&n->encrypt); new_free(&n->othername); break; case 230: { char *dir = NULL; if (n->othername) { err = dcc_printf(snum, "cwd %s\r\n", n->othername); if (do_hook(FTP_LIST, "%d Changing directory to %s", comm, n->othername)) put_it("%s", convert_output_format("%gFTP%n Changing directory to $0-", "%s", n->othername)); } new_free(&n->encrypt); new_free(&n->userhost); new_free(&n->othername); new_free(&dir); break; } case 421: erase_dcc_info(snum, 0, NULL); close_socketread(snum); break; default: break; } if (do_hook(FTP_LIST, "%d %s", comm, buf)) put_it("%s", convert_output_format("%gFTP%n $0-", "%s", buf)); return err; } void start_ftp(int snum) { SocketList *s; DCC_int *n; char *buf = NULL; int i = 0; s = get_socket(snum); n = (DCC_int *)s->info; if (s->flags & DCC_WAIT) { struct sockaddr_in remaddr; socklen_t rl = sizeof(remaddr); /* maybe we should login here. */ if (getpeername(snum, (struct sockaddr *) &remaddr, &rl) != -1) { s->flags = DCC_ACTIVE|DCC_FTPOPEN; return; } erase_dcc_info(snum, 0, "DCC ftp lost"); close_socketread(snum); return; } buf = alloca(n->blocksize+1); *buf = 0; switch(dgets(buf, snum, 1, n->blocksize, NULL)) { case -1: i = -1; break; case 0: break; default: { int comm = 0; char *p; if ((p = strrchr(buf, '\r'))) *p = 0; if ((p = strrchr(buf, '\n'))) *p = 0; if ((comm = my_atol(buf))) next_arg(buf, &buf); i = handle_ftp(comm, snum, s, buf); break; } } if (i == -1) { erase_dcc_info(snum, 0, NULL); close_socketread(snum); } } void open_ftpget(SocketList *s, char *args) { DCC_int *new; struct sockaddr_in data_addr = { 0 }; socklen_t len = sizeof(struct sockaddr_in); char tmp[BIG_BUFFER_SIZE+1]; int data = -1, s1 = -1; char *p, *bufptr; off_t filesize = 0; char *filename = NULL; if ((data = open_listen_port(s->is_read)) == -1) return; dcc_printf(s->is_read, "retr %s\n", args); memset(tmp, 0, sizeof(tmp)); bufptr = tmp; while (1) { if (dgets(bufptr, s->is_read, 1, BIG_BUFFER_SIZE, NULL) == -1 && dgets_errno > 0) goto error_ftp; if (*bufptr == '5') goto error_ftp; else if (strstr(tmp, "BINARY mode data connection")) { int i = 0; char *q = tmp; for (i = 0; i < 9; i++) p = next_arg(q, &q); if (p) { p++; filesize = my_atol(p); } break; } } len = sizeof(struct sockaddr_in); if ((s1 = my_accept(data, (struct sockaddr *) &data_addr, &len)) < 0) return; close(data); #if defined(WINNT) || defined(__EMX__) if ((p = strrchr(args, '/')) || (p = strrchr(args, '\\'))) #else if ((p = strrchr(args, '/'))) #endif filename = ++p; else filename = args; add_socketread(s1, 0, DCC_FTPGET|DCC_ACTIVE, s->server, read_ftp_file, NULL); new = new_malloc(sizeof(DCC_int)); { char *t, *expand; expand = m_sprintf("%s/%s", get_string_var(DCC_DLDIR_VAR), filename); t = expand_twiddle(expand); new->file = open(t?t:expand?expand:filename, O_WRONLY|O_CREAT|O_TRUNC | O_BINARY, 0644); new_free(&t); new_free(&expand); } new->struct_type = DCC_STRUCT_TYPE; new->filesize = filesize; new->filename = m_strdup(filename); get_time(&new->starttime); get_time(&new->lasttime); set_socketinfo(s1, new); s->flags |= DCC_WAIT; if (do_hook(FTP_LIST, "%s %s", "FTP Attempting to get", filename)) put_it("%s", convert_output_format("$G %gFTP%n Attempting to get $0", "%s", filename)); return; error_ftp: close(data); chop(tmp, 2); put_it("%s", convert_output_format("$G %gFTP%n $0-", "%s", tmp)); return; } int dcc_ftpcommand (char *host, char *args) { SocketList *s; s = find_dcc(host, "ftpopen", NULL, DCC_FTPOPEN, 0, 1, -1); if (s) { char *command = next_arg(args, &args); char *t_host; if (s->flags & DCC_WAIT) { if (do_hook(FTP_LIST, "%s", "FTP connection is busy")) put_it("%s", convert_output_format("$G %gFTP%n connection is busy.", NULL, NULL)); return 1; } if (command && *command) { if (!my_strnicmp(command, "ls",2) || !my_strnicmp(command, "dir",3)) { int sock, s1; DCC_int *new; struct sockaddr_in data_addr = { 0 }; socklen_t len; char tmp[BIG_BUFFER_SIZE+1], *bufptr; if ((sock = open_listen_port(s->is_read)) == -1) return -1; dcc_printf(s->is_read, "list -a%s%s\r\n", (args && *args) ?space:empty_string, (args && *args) ? args : empty_string); memset(tmp, 0, sizeof(tmp)); bufptr = tmp; while (1) { if (dgets(bufptr, s->is_read, 1, BIG_BUFFER_SIZE, NULL) == -1 && dgets_errno > 0) goto error_port; if (*bufptr == '5') goto error_port; else if (strstr(tmp, "150 Opening BINARY mode data connection")) break; } len = sizeof(struct sockaddr_in); set_blocking(sock); alarm(10); s1 = accept(sock, (struct sockaddr *) &data_addr, &len); alarm(0); close(sock); if (s1 != -1) { add_socketread(s1, 0, DCC_FTPCOMMAND|DCC_ACTIVE, s->server, start_ftp, NULL); new = new_malloc(sizeof(DCC_int)); new->struct_type = DCC_STRUCT_TYPE; get_time(&new->starttime); get_time(&new->lasttime); new->blocksize = BIG_BUFFER_SIZE; set_socketinfo(s1, new); } else bitchsay("FTP data connection failed."); } else if (!my_strnicmp(command, "more", 3)) dcc_printf(s->is_read, "stat %s\n", args ? args : empty_string); else if (!my_strnicmp(command, "cd", 2)) dcc_printf(s->is_read, "%s%s%s\n", (args && *args) ? "cwd" : "pwd", (args && *args) ? space:empty_string, (args && *args) ?args:empty_string); else if (!my_strnicmp(command, "get",3) && args && *args) open_ftpget(s, args); else dcc_printf(s->is_read, "%s%s%s\n", command, (args && *args) ? space:empty_string, (args && *args) ? args:empty_string); t_host = alloca(strlen(host)+4); strcpy(t_host, "-"); strcat(t_host, host); addtabkey(t_host, "msg", 0); } } else { if (do_hook(FTP_LIST, "%s", "FTP is not connected")) put_it("%s", convert_output_format("$G %gFTP%n is not connected.", NULL, NULL)); return 0; } return 1; error_port: return -1; } char *parse_ncftp(char *buffer, char **hostname) { char *dir = NULL, *p; /*bitchx,bitchx.com,panasync,,,/home/panasync,I,,34ce4360,1,*/ if (!(p = strchr(buffer, ','))) return NULL; *p++ = 0; *hostname = p; if (!(p = strchr(p, ','))) return NULL; *p++ = 0; if (!(p = strchr(p, ','))) return NULL; *p++ = 0; if (!(p = strchr(p, ','))) return NULL; *p++ = 0; if (!(p = strchr(p, ','))) return NULL; *p++ = 0; dir = p; if (!(p = strchr(p, ','))) return NULL; *p = 0; return (dir && *dir) ? dir : NULL; } char *read_ncftp_config(char **hostname) { char *tmp, *file = NULL; char *buffer; char *dir = NULL; struct stat sb; FILE *f; tmp = m_sprintf("~/.ncftp/bookmarks"); file = expand_twiddle(tmp); if ((stat(file, &sb) != -1) && (f = fopen(file, "r"))) { char *hst = NULL; buffer = alloca(sb.st_size+1); freadln(f, buffer, sb.st_size + 1); while(!feof(f)) { if ((freadln(f, buffer, sb.st_size + 1))) { if (*buffer == '#') continue; dir = parse_ncftp(buffer, &hst); if (hst) { if (!my_stricmp(hst, *hostname)) break; else if (!my_stricmp(*hostname, buffer)) { malloc_strcpy(hostname, hst); break; } } dir = NULL; } } fclose(f); } new_free(&tmp); new_free(&file); return dir ? m_strdup(dir) : NULL; } void dcc_ftpopen(char *command, char *args) { char u[] = "anonymous"; char p[] = "- bxuser@"; char *host = NULL, *user = NULL, *pass = NULL, *dir = NULL, *t_host = NULL; unsigned short port = 21; int blocksize = 2048; int snum; SocketList *s; if (!(t_host = next_arg(args, &args))) { put_it ("%s /dcc ftp hostname user passwd [-p port] [-b blocksize]", convert_output_format("$G %RDCC%n", NULL, NULL)); return; } host = m_strdup(t_host); while (args && *args) { char *t; if (!my_strnicmp(args, "-p", 2)) { next_arg(args, &args); port = my_atol(next_arg(args, &args)); continue; } if (!my_strnicmp(args, "-b", 2)) { next_arg(args, &args); blocksize = my_atol(next_arg(args, &args)); continue; } else if ((t = next_arg(args, &args))) { if (!user) user = t; else malloc_strcpy(&pass, t); } } if (!user) user = u; if (!pass) pass = m_sprintf("%s%s", p, hostname); dir = read_ncftp_config(&host); if ((s = find_dcc(host, "ftpopen", NULL, DCC_FTPOPEN, 0, -1, -1))) { put_it("%s", convert_output_format("$G %GFTP%n A previous DCC FTP to $0 exists", "%s", host)); new_free(&host); return; } #if defined(WINNT) || defined(__EMX__) if ((snum = connect_by_number(host, &port, SERVICE_CLIENT, PROTOCOL_TCP, 0)) < 0) #else if ((snum = connect_by_number(host, &port, SERVICE_CLIENT, PROTOCOL_TCP, 1)) < 0) #endif { put_it("%s", convert_output_format("$G %gFTP%n command failed connect", NULL, NULL)); new_free(&host); return; } else { DCC_int *new; add_socketread(snum, port, DCC_WAIT|DCC_FTPOPEN, host, start_ftp, NULL); new = new_malloc(sizeof(DCC_int)); new->struct_type = DCC_STRUCT_TYPE; new->remport = port; new->blocksize = blocksize; get_time(&new->starttime); get_time(&new->lasttime); malloc_strcpy(&new->userhost, user); new->encrypt = pass; /* these are not a mem leak */ new->user = host; /* free'd in handle_ftp() */ malloc_strcpy(&new->filename, "ftpopen"); new->othername = dir; set_socketinfo(snum, new); } t_host = alloca(strlen(host)+4); strcpy(t_host, "-"); strcat(t_host, host); addtabkey(t_host, "msg", 0); return; } void dcc_rename(char *command, char *args) { DCC_List *tmp; DCC_int *n; char *nick, *filename; nick = next_arg(args, &args); filename = new_next_arg(args, &args); if (!nick || !filename || !*filename) { put_it("%s", convert_output_format("$G /DCC rename nick filename", NULL, NULL)); return; } for (tmp = pending_dcc; tmp; tmp = tmp->next) { if (my_stricmp(tmp->nick, nick)) continue; n = (DCC_int *)tmp->sock.info; malloc_strcpy(&n->filename, filename); break; } } static int check_dcc_init(char *nick, char *type, char *description, char *address, char *port, char *size, char *extra, char *uhost) { int i; unsigned long filesize; unsigned long TempLong; unsigned int TempInt; if (!parse_offer_params(address, port, size, &TempLong, &TempInt, &filesize)) return 0; for (i = 0; dcc_types[i]->name; i++) { if (!my_stricmp(type, dcc_types[i]->name)) break; } if (!dcc_types[i]->name) return 0; if (dcc_types[i]->init_func) return (*dcc_types[i]->init_func)(type, nick, uhost, description, size, extra, TempLong, TempInt); return 0; } int BX_add_dcc_bind(char *name, char *module, void *init_func, void *open_func, void *input, void *output, void *close_func) { int i; for (i = 0; dcc_types[i]->name; i++) { if (!my_stricmp(dcc_types[i]->name, name)) break; } if (i >= 0xfe) return 0; if (!dcc_types[i]) { RESIZE(dcc_types, struct _dcc_types_ *, i + 2); dcc_types[i] = new_malloc(sizeof(struct _dcc_types_)); } if (!dcc_types[i]->name) malloc_strcpy(&dcc_types[i]->name, name); malloc_strcpy(&dcc_types[i]->module, module); dcc_types[i]->init_func = init_func; dcc_types[i]->open_func = open_func; dcc_types[i]->input = input; dcc_types[i]->output = output; dcc_types[i]->close_func = close_func; dcc_types[i]->type = i; return i; } int BX_remove_dcc_bind(char *name, int type) { int i = type & DCC_TYPES; if (!dcc_types[i]->module) return 0; dcc_types[i]->init_func = NULL; dcc_types[i]->open_func = NULL; dcc_types[i]->input = NULL; dcc_types[i]->output = NULL; dcc_types[i]->close_func = NULL; new_free(&dcc_types[i]->module); if (i > DCC_FTPSEND) { new_free(&dcc_types[i]->name); new_free(&dcc_types[i]); /* RESIZE(dcc_types, struct _dcc_types *, i - 1);*/ } return 1; } int BX_remove_all_dcc_binds(char *name) { int ret = 0; int i, j; /* scan to end of list */ for (i = 0; dcc_types[i]->name; i++); i--; for (j = i; j > 0; j--) ret += remove_dcc_bind(dcc_types[j]->name, dcc_types[j]->type); return ret; } void init_dcc_table(void) { int i; for (i = 0; _dcc_types[i].name; i++); RESIZE(dcc_types, struct _dcc_types_ *, i + 1); for (i = 0; _dcc_types[i].name; i++) { dcc_types[i] = new_malloc(sizeof(struct _dcc_types_)); dcc_types[i]->name = m_strdup(_dcc_types[i].name); dcc_types[i]->type = _dcc_types[i].type; } dcc_types[i] = new_malloc(sizeof(struct _dcc_types_)); } char *get_dcc_info(SocketList *s, DCC_int *n, int i) { char local_type[80]; *local_type = 0; if (s->flags & DCC_TDCC) strcpy(local_type, "T"); strcat(local_type, dcc_types[s->flags & DCC_TYPES]->name); return m_sprintf("%s %s %s %ld %lu %lu %lu %s #%d %d", local_type, s->server, s->flags & DCC_OFFER ? "Offer": s->flags & DCC_WAIT ? "Wait": s->flags & DCC_ACTIVE? "Active":"Unknown", (long)n->starttime.tv_sec, (unsigned long)n->transfer_orders.byteoffset, (unsigned long)n->bytes_sent, (unsigned long)n->bytes_read, n->filename, i, n->server); } void dcc_raw_transmit (char *user, char *text, char *type) { return; } #if 0 /* * Usage: $listen() */ char *dcc_raw_listen (unsigned short port) { DCC_list *Client; char *PortName; set_display_target(NULL, LOG_DCC); if (port && port < 1025) { say("May not bind to a privileged port"); set_display_target(NULL, LOG_CURRENT); return NULL; } PortName = ltoa(port); Client = dcc_searchlist("raw_listen", PortName, DCC_RAW_LISTEN, 1, NULL, -1); if (Client->flags & DCC_ACTIVE) { say("A previous DCC RAW_LISTEN on %s exists", PortName); set_display_target(NULL, LOG_CURRENT); return NULL; } if ((Client->read = connect_by_number(NULL, &port, SERVICE_SERVER, PROTOCOL_TCP)) < 0) { say("Couldnt establish listening socket: [%d] %s", Client->read, strerror(errno)); Client->flags |= DCC_DELETE; set_display_target(NULL, LOG_CURRENT); return NULL; } new_open(Client->read); get_time(&Client->starttime); Client->local_port = port; Client->flags |= DCC_ACTIVE; Client->user = m_strdup(ltoa(Client->local_port)); set_display_target(NULL, LOG_CURRENT); return m_strdup(Client->user); } /* * Usage: $connect( ) */ char *dcc_raw_connect(char *host, u_short port) { DCC_list *Client; char *PortName; struct in_addr address; struct hostent *hp; set_display_target(NULL, LOG_DCC); if ((address.s_addr = inet_addr(host)) == (unsigned) -1) { if (!(hp = gethostbyname(host))) { say("Unknown host: %s", host); set_display_target(NULL, LOG_CURRENT); return m_strdup(empty_string); } memmove(&address, hp->h_addr, sizeof(address)); } Client = dcc_searchlist(host, ltoa(port), DCC_RAW, 1, NULL, -1); if (Client->flags & DCC_ACTIVE) { say("A previous DCC RAW to %s on %s exists", host, ltoa(port)); set_display_target(NULL, LOG_CURRENT); return m_strdup(empty_string); } /* Sorry. The missing 'htons' call here broke $connect() */ Client->remport = htons(port); memmove((char *)&Client->remote, (char *)&address, sizeof(address)); Client->flags = DCC_THEIR_OFFER | DCC_RAW; if (!dcc_open(Client)) { set_display_target(NULL, LOG_CURRENT); return m_strdup(empty_string); } PortName = ltoa(Client->read); Client->user = m_strdup(PortName); if (do_hook(DCC_RAW_LIST, "%s %s E %d", PortName, host, port)) if (do_hook(DCC_CONNECT_LIST,"%s RAW %s %d",PortName, host, port)) say("DCC RAW connection to %s on %s via %d established", host, PortName, port); set_display_target(NULL, LOG_CURRENT); return m_strdup(PortName); } #endif char *dcc_raw_connect(char *host, u_short port) { return m_strdup("-1"); } char *dcc_raw_listen(int port) { #if 0 SocketList *Client; char *PortName; set_display_target(NULL, LOG_DCC); if (port && port < 1025) { say("May not bind to a privileged port"); set_display_target(NULL, LOG_CURRENT); return NULL; } PortName = ltoa(port); Client = find_dcc(PortName, NULL, "raw_listen", DCC_RAW_LISTEN, 1, 0, -1); Client = dcc_searchlist("raw_listen", PortName, DCC_RAW_LISTEN, 1, NULL, -1); if (Client->flags & DCC_ACTIVE) { say("A previous DCC RAW_LISTEN on %s exists", PortName); set_display_target(NULL, LOG_CURRENT); return NULL; } if ((Client->read = connect_by_number(NULL, &port, SERVICE_SERVER, PROTOCOL_TCP)) < 0) { say("Couldnt establish listening socket: [%d] %s", Client->read, strerror(errno)); Client->flags |= DCC_DELETE; set_display_target(NULL, LOG_CURRENT); return NULL; } new_open(Client->read); get_time(&Client->starttime); Client->local_port = port; Client->flags |= DCC_ACTIVE; Client->user = m_strdup(ltoa(Client->local_port)); set_display_target(NULL, LOG_CURRENT); return m_strdup(Client->user); #endif return m_strdup("-1"); } int close_dcc_number(int number) { if (!check_dcc_socket(number)) return 0; erase_dcc_info(number, 1, NULL); close_socketread(number); return 1; }