/* * iroffer by David Johnson (PMG) * Copyright (C) 1998-2005 David Johnson * * By using this file, you agree to the terms and conditions set * forth in the GNU General Public License. More information is * available in the README file. * * If you received this file without documentation, it can be * downloaded from http://iroffer.org/ * * @(#) iroffer_main.c 1.245@(#) * pmg@wellington.i202.centerclick.org|src/iroffer_main.c|20050313225819|23935 * */ /* include the headers */ #define GEX #include "iroffer_config.h" #include "iroffer_defines.h" #include "iroffer_headers.h" #include "iroffer_globals.h" /* local functions */ static void mainloop(void); static void parseline(char *line); static void privmsgparse(const char* type, char* line); static void autosendf(char* line); static char* addtoqueue(const char* nick, const char* hostname, int pack); static int parsecmdline(int argc, char *argv[]); /* main */ int main(int argc, char *argv[]) { int i; int first_config_arg; initvars(); switch( parsecmdline( argc, argv ) ) { case PCL_OK: break; case PCL_BAD_OPTION: printf("\n" "iroffer v" VERSIONLONG " by PMG, see http://iroffer.org/\n" "\n" "Usage: %s [-vc] [-bdkn" #if !defined(_OS_CYGWIN) "s" #endif "]" #if !defined(NO_SETUID) " [-u user]" #endif #if !defined(NO_CHROOT) " [-t dir]" #endif " configfile [ configfile ... ]\n" " -v Print version and exit.\n" " -c Generate encrypted password and exit.\n" " -d Increase debug level\n" " -b Go to background mode\n" " -k Attempt to adjust ulimit to allow core files\n" " -n No colors in foreground mode\n" #if !defined(_OS_CYGWIN) " -s No screen manipulation in foreground mode\n" #endif #if !defined(NO_SETUID) " -u user Run as user (you have to start as root).\n" #endif #if !defined(NO_CHROOT) " -t dir Chroot to dir (you have to start as root).\n" #endif "\n", argv[0]); exit(0); case PCL_SHOW_VERSION: printf("iroffer v" VERSIONLONG " by PMG, see http://iroffer.org/\n"); exit(0); case PCL_GEN_PASSWORD: createpassword(); exit(0); default: break; } #if defined(_OS_CYGWIN) gdata.noscreen = 1; #endif first_config_arg = optind; for (i=0; i= argc) { fprintf(stderr,"%s: no configuration file specifed\n", argv[0]); return PCL_BAD_OPTION; } return PCL_OK; } static void select_dump(const char *desc, int highests) { int ii; if (!gdata.attop) gototop(); ioutput(CALLTYPE_MULTI_FIRST,OUT_S,COLOR_CYAN, "select %s: [read",desc); for (ii=0; iistatus == DCCCHAT_CONNECTING) { FD_SET(chat->fd, &gdata.writeset); highests = max2(highests, chat->fd); } else if (chat->status != DCCCHAT_UNUSED) { FD_SET(chat->fd, &gdata.readset); highests = max2(highests, chat->fd); } } j = gdata.xdccsent[(gdata.curtime)%XDCC_SENT_SIZE] + gdata.xdccsent[(gdata.curtime-1)%XDCC_SENT_SIZE] + gdata.xdccsent[(gdata.curtime-2)%XDCC_SENT_SIZE] + gdata.xdccsent[(gdata.curtime-3)%XDCC_SENT_SIZE]; if ( gdata.maxb && ((gdata.xdccsent[(gdata.curtime)%XDCC_SENT_SIZE] + gdata.xdccsent[(gdata.curtime-1)%XDCC_SENT_SIZE] + gdata.xdccsent[(gdata.curtime-2)%XDCC_SENT_SIZE] + gdata.xdccsent[(gdata.curtime-3)%XDCC_SENT_SIZE]) >= gdata.maxb*1024)) { overlimit = 1; } else { overlimit = 0; } tr = irlist_get_head(&gdata.trans); while(tr) { if (tr->tr_status == TRANSFER_STATUS_LISTENING) { FD_SET(tr->listensocket, &gdata.readset); highests = max2(highests, tr->listensocket); } if (tr->tr_status == TRANSFER_STATUS_SENDING) { if (!overlimit && !tr->overlimit) { FD_SET(tr->clientsocket, &gdata.writeset); highests = max2(highests, tr->clientsocket); } if (changequartersec || ((tr->bytessent-tr->lastack) > 512*1024)) { FD_SET(tr->clientsocket, &gdata.readset); highests = max2(highests, tr->clientsocket); } } if (tr->tr_status == TRANSFER_STATUS_WAITING) { FD_SET(tr->clientsocket, &gdata.readset); highests = max2(highests, tr->clientsocket); } tr = irlist_get_next(tr); } ul = irlist_get_head(&gdata.uploads); while(ul) { if (ul->ul_status == UPLOAD_STATUS_CONNECTING) { FD_SET(ul->clientsocket, &gdata.writeset); highests = max2(highests, ul->clientsocket); } if (ul->ul_status == UPLOAD_STATUS_GETTING) { FD_SET(ul->clientsocket, &gdata.readset); highests = max2(highests, ul->clientsocket); } ul = irlist_get_next(ul); } if (gdata.md5build.file_fd != FD_UNUSED) { assert(gdata.md5build.xpack); FD_SET(gdata.md5build.file_fd, &gdata.readset); highests = max2(highests, gdata.md5build.file_fd); } updatecontext(); timestruct.tv_sec = 0; timestruct.tv_usec = 250*1000; if (gdata.debug > 3) { select_dump("try", highests); } if (gdata.attop) gotobot(); tostdout_write(); if (select(highests+1, &gdata.readset, &gdata.writeset, NULL, ×truct) < 0) { if (errno != EINTR) { outerror(OUTERROR_TYPE_WARN,"Select returned an error: %s",strerror(errno)); usleep(10000); /* prevent fast spinning */ } /* data is undefined on error, zero and continue */ FD_ZERO(&gdata.readset); FD_ZERO(&gdata.writeset); } if (gdata.debug > 3) { select_dump("got", highests); } if (gdata.needsshutdown) { gdata.needsshutdown = 0; shutdowniroffer(); } if (gdata.needsreap) { pid_t child; int status; gdata.needsreap = 0; while ((child = waitpid(-1, &status, WNOHANG)) > 0) { if (gdata.serverstatus == SERVERSTATUS_RESOLVING) { if (child == gdata.serv_resolv.child_pid) { /* lookup failed */ #ifdef NO_WSTATUS_CODES ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_RED, "Unable to resolve server %s (status=0x%.8X)", gdata.curserver.hostname, status); #else #ifndef NO_HOSTCODES if (WIFEXITED(status) && (WEXITSTATUS(status) >= 20) && (WEXITSTATUS(status) <= 23)) { const char *errstr; switch (WEXITSTATUS(status)) { case 20: errstr = "host not found"; break; case 21: errstr = "no ip address"; break; case 22: errstr = "non-recoverable name server"; break; case 23: errstr = "try again later"; break; default: errstr = "unknown"; break; } ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_RED, "Unable to resolve server %s (%s)", gdata.curserver.hostname, errstr); } else #endif { ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_RED, "Unable to resolve server %s (status=0x%.8X, %s: %d)", gdata.curserver.hostname, status, WIFEXITED(status) ? "exit" : WIFSIGNALED(status) ? "signaled" : "??", WIFEXITED(status) ? WEXITSTATUS(status) : WIFSIGNALED(status) ? WTERMSIG(status) : 0); } #endif gdata.serverstatus = SERVERSTATUS_NEED_TO_CONNECT; } /* else this is an old child, ignore */ } if (child == gdata.serv_resolv.child_pid) { /* cleanup */ close(gdata.serv_resolv.sp_fd[0]); FD_CLR(gdata.serv_resolv.sp_fd[0], &gdata.readset); gdata.serv_resolv.sp_fd[0] = 0; gdata.serv_resolv.child_pid = 0; } } } /*----- one second check ----- */ updatecontext(); if (gettimeofday(×truct, NULL) < 0) { outerror(OUTERROR_TYPE_CRASH,"gettimeofday() failed! %s\n",strerror(errno)); } gdata.curtimems = (((unsigned long long)timestruct.tv_sec) * 1000) + (((unsigned long long)timestruct.tv_usec) / 1000); gdata.curtime = timestruct.tv_sec; /* adjust for drift and cpu usage */ if ((gdata.curtimems > (last250ms+1000)) || (gdata.curtimems < last250ms)) { /* skipped forward or backwards, correct */ last250ms = gdata.curtimems-250; } if (gdata.curtimems >= (last250ms+250)) { changequartersec = 1; /* note bandwidth limiting requires no drift! */ last250ms += 250; } else { changequartersec = 0; } changesec = 0; if (gdata.curtime != lasttime) { if (gdata.curtime < lasttime-3) { if (!gdata.attop) gototop(); outerror(OUTERROR_TYPE_WARN,"System Time Changed Backwards %lim %lis!!\n", (long)(lasttime-gdata.curtime)/60,(long)(lasttime-gdata.curtime)%60); } if (gdata.curtime > lasttime+10) { if (!gdata.attop) gototop(); outerror(OUTERROR_TYPE_WARN,"System Time Changed Forward or Mainloop Skipped %lim %lis!!\n", (long)(gdata.curtime-lasttime)/60,(long)(gdata.curtime-lasttime)%60); if (gdata.debug > 0) { dumpcontext(); } } lasttime = gdata.curtime; changesec = 1; } if (changesec && lasttime/60/60 != lasthour) { lasthour = lasttime/60/60; changehour = 1; } if (changesec && lasttime/60 != lastmin) { lastmin = lasttime/60; changemin = 1; } updatecontext(); if (changesec) { gdata.totaluptime++; xdccsent = 0; for (i=0; i gdata.sentrecord) gdata.sentrecord = ((float)xdccsent)/XDCC_SENT_SIZE/1024.0; gdata.xdccsent[(gdata.curtime+1)%XDCC_SENT_SIZE] = 0; } if (changequartersec) { tr = irlist_get_head(&gdata.trans); while(tr) { if ( !tr->nomax && (tr->xpack->maxspeed > 0)) { tr->tx_bucket += tr->xpack->maxspeed * (1024 / 4); tr->tx_bucket = min2(tr->tx_bucket, MAX_TRANSFER_TX_BURST_SIZE * tr->xpack->maxspeed * 1024); } tr = irlist_get_next(tr); } } updatecontext(); /*----- see if anything waiting on console ----- */ gdata.needsclear = 0; if (!gdata.background && FD_ISSET(fileno(stdin), &gdata.readset)) parseconsole(); updatecontext(); /*----- see if gdata.ircserver is sending anything to us ----- */ if (gdata.serverstatus == SERVERSTATUS_CONNECTED && FD_ISSET(gdata.ircserver, &gdata.readset)) { char tempbuffa[INPUT_BUFFER_LENGTH]; gdata.lastservercontact = gdata.curtime; gdata.servertime = 0; length = read (gdata.ircserver, &tempbuffa, INPUT_BUFFER_LENGTH); if (length < 1) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_RED,"Closing Server Connection: %s",(length<0) ? strerror(errno) : "Closed"); if (gdata.exiting) { gdata.recentsent = 0; } FD_CLR(gdata.ircserver, &gdata.readset); /* * cygwin close() is broke, if outstanding data is present * it will block until the TCP connection is dead, sometimes * upto 10-20 minutes, calling shutdown() first seems to help */ shutdown(gdata.ircserver, SHUT_RDWR); close(gdata.ircserver); mydelete(gdata.curserveractualname); gdata.serverstatus = SERVERSTATUS_NEED_TO_CONNECT; } else { j=strlen(server_input_line); for (i=0; i= 0) { gdata.ourip = ntohl(localaddr.sin_addr.s_addr); if (gdata.debug > 0) { ioutput(CALLTYPE_NORMAL,OUT_S,COLOR_YELLOW,"ourip = %lu.%lu.%lu.%lu", (gdata.ourip >> 24) & 0xFF, (gdata.ourip >> 16) & 0xFF, (gdata.ourip >> 8) & 0xFF, (gdata.ourip ) & 0xFF ); } } else outerror(OUTERROR_TYPE_WARN,"couldn't get ourip"); } initirc(); } } if ((gdata.serverstatus == SERVERSTATUS_RESOLVING) && FD_ISSET(gdata.serv_resolv.sp_fd[0], &gdata.readset)) { struct in_addr remote; length = read(gdata.serv_resolv.sp_fd[0], &remote, sizeof(struct in_addr)); kill(gdata.serv_resolv.child_pid, SIGKILL); FD_CLR(gdata.serv_resolv.sp_fd[0], &gdata.readset); if (length != sizeof(struct in_addr)) { ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_RED, "Error resolving server %s", gdata.curserver.hostname); gdata.serverstatus = SERVERSTATUS_NEED_TO_CONNECT; } else { /* continue with connect */ if (connectirc2(&remote)) { /* failed */ gdata.serverstatus = SERVERSTATUS_NEED_TO_CONNECT; } } } if (changesec && gdata.serverstatus == SERVERSTATUS_RESOLVING) { int timeout; timeout = CTIMEOUT + (gdata.serverconnectbackoff * CBKTIMEOUT); if (gdata.lastservercontact + timeout < gdata.curtime) { kill(gdata.serv_resolv.child_pid, SIGKILL); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR,"Server Resolve Timed Out (%d seconds)",timeout); gdata.serverstatus = SERVERSTATUS_NEED_TO_CONNECT; } } if (changesec && gdata.serverstatus == SERVERSTATUS_TRYING) { int timeout; timeout = CTIMEOUT + (gdata.serverconnectbackoff * CBKTIMEOUT); if (gdata.lastservercontact + timeout < gdata.curtime) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR,"Server Connection Timed Out (%d seconds)",timeout); FD_CLR(gdata.ircserver, &gdata.readset); /* * cygwin close() is broke, if outstanding data is present * it will block until the TCP connection is dead, sometimes * upto 10-20 minutes, calling shutdown() first seems to help */ shutdown(gdata.ircserver, SHUT_RDWR); close(gdata.ircserver); gdata.serverstatus = SERVERSTATUS_NEED_TO_CONNECT; } } if (gdata.needsswitch) { gdata.needsswitch = 0; switchserver(-1); } updatecontext(); ul = irlist_get_head(&gdata.uploads); while(ul) { /*----- see if uploads are sending anything to us ----- */ if (ul->ul_status == UPLOAD_STATUS_GETTING && FD_ISSET(ul->clientsocket, &gdata.readset)) { l_transfersome(ul); } if (ul->ul_status == UPLOAD_STATUS_CONNECTING && FD_ISSET(ul->clientsocket, &gdata.writeset)) { int callval_i; int connect_error; int connect_error_len = sizeof(connect_error); callval_i = getsockopt(ul->clientsocket, SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len); if (callval_i < 0) { outerror(OUTERROR_TYPE_WARN, "Couldn't determine upload connection status: %s", strerror(errno)); l_closeconn(ul,"Upload Connection Failed status:",errno); } else if (connect_error) { l_closeconn(ul,"Upload Connection Failed",connect_error); } if ((callval_i < 0) || connect_error) { FD_CLR(ul->clientsocket, &gdata.writeset); } else { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_MAGENTA,"Upload Connection Established"); ul->ul_status = UPLOAD_STATUS_GETTING; FD_CLR(ul->clientsocket, &gdata.writeset); notice(ul->nick,"DCC Connection Established"); ul->connecttime = gdata.curtime; if (set_socket_nonblocking(ul->clientsocket,0) < 0 ) { outerror(OUTERROR_TYPE_WARN,"Couldn't Set Blocking"); } } } if (changesec && ul->ul_status == UPLOAD_STATUS_CONNECTING && ul->lastcontact + CTIMEOUT < gdata.curtime) { FD_CLR(ul->clientsocket, &gdata.readset); l_closeconn(ul,"Upload Connection Timed Out",0); } if (changesec) { l_istimeout(ul); } if (changesec && ul->ul_status == UPLOAD_STATUS_DONE) { mydelete(ul->nick); mydelete(ul->hostname); mydelete(ul->file); ul = irlist_delete(&gdata.uploads, ul); } else { ul = irlist_get_next(ul); } } updatecontext(); /*----- see if dccchat is sending anything to us ----- */ for (chat = irlist_get_head(&gdata.dccchats); chat; chat = irlist_get_next(chat)) { if ((chat->status == DCCCHAT_CONNECTING) && FD_ISSET(chat->fd, &gdata.writeset)) { int callval_i; int connect_error; int connect_error_len = sizeof(connect_error); callval_i = getsockopt(chat->fd, SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len); if (callval_i < 0) { outerror(OUTERROR_TYPE_WARN, "Couldn't determine dcc connection status: %s", strerror(errno)); notice(chat->nick, "DCC Chat Connect Attempt Failed: %s", strerror(errno)); } else if (connect_error) { ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "DCC Chat Connect Attempt Failed: %s", strerror(connect_error)); notice(chat->nick, "DCC Chat Connect Attempt Failed: %s", strerror(connect_error)); } if ((callval_i < 0) || connect_error) { shutdowndccchat(chat,0); } else { setupdccchatconnected(chat); } } if ((chat->status != DCCCHAT_UNUSED) && FD_ISSET(chat->fd, &gdata.readset)) { char tempbuffa[INPUT_BUFFER_LENGTH]; switch (chat->status) { case DCCCHAT_LISTENING: setupdccchataccept(chat); break; case DCCCHAT_AUTHENTICATING: case DCCCHAT_CONNECTED: memset(tempbuffa, 0, INPUT_BUFFER_LENGTH); length = read(chat->fd, &tempbuffa, INPUT_BUFFER_LENGTH); if (length < 1) { ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "DCC Chat Lost: %s", (length<0) ? strerror(errno) : "Closed"); notice(chat->nick, "DCC Chat Lost: %s", (length<0) ? strerror(errno) : "Closed"); shutdowndccchat(chat,0); /* deleted below */ } else { j=strlen(chat->dcc_input_line); for (i=0; idcc_input_line[j-1] == 0x0D)) { j--; } chat->dcc_input_line[j] = '\0'; parsedccchat(chat, chat->dcc_input_line); j = 0; } else { chat->dcc_input_line[j] = tempbuffa[i]; j++; } } chat->dcc_input_line[j] = '\0'; } break; case DCCCHAT_CONNECTING: case DCCCHAT_UNUSED: default: outerror(OUTERROR_TYPE_CRASH, "Unexpected dccchat state %d", chat->status); break; } } } updatecontext(); i = j = gdata.cursendptr++ % max2(irlist_size(&gdata.trans),1); tr = irlist_get_nth(&gdata.trans, i); /* first: do from cur to end */ while(tr) { if (tr->tr_status == TRANSFER_STATUS_SENDING) { /*----- look for transfer some ----- send at least once a second, or more if necessary */ if (changequartersec || FD_ISSET(tr->clientsocket, &gdata.writeset)) { t_transfersome(tr); } } tr = irlist_get_next(tr); } /* second: do from begin to cur-1 */ tr = irlist_get_head(&gdata.trans); while(tr && j--) { if (tr->tr_status == TRANSFER_STATUS_SENDING) { /*----- look for transfer some ----- send at least once a second, or more if necessary */ if (changequartersec || FD_ISSET(tr->clientsocket, &gdata.writeset)) { t_transfersome(tr); } } tr = irlist_get_next(tr); } tr = irlist_get_head(&gdata.trans); while(tr) { /*----- look for listen reminders ----- */ if (changesec && (tr->tr_status == TRANSFER_STATUS_LISTENING) && ((gdata.curtime - tr->lastcontact) >= 30) && (tr->reminded == 0)) { t_remind(tr); } if (changesec && (tr->tr_status == TRANSFER_STATUS_LISTENING) && ((gdata.curtime - tr->lastcontact) >= 90) && (tr->reminded == 1) && !gdata.quietmode) { t_remind(tr); } if (changesec && (tr->tr_status == TRANSFER_STATUS_LISTENING) && ((gdata.curtime - tr->lastcontact) >= 150) && (tr->reminded == 2) && !gdata.quietmode) { t_remind(tr); } /*----- look for listen->connected ----- */ if ((tr->tr_status == TRANSFER_STATUS_LISTENING) && FD_ISSET(tr->listensocket, &gdata.readset)) { t_establishcon(tr); } /*----- look for junk to read ----- */ if (((tr->tr_status == TRANSFER_STATUS_SENDING) || (tr->tr_status == TRANSFER_STATUS_WAITING)) && FD_ISSET(tr->clientsocket, &gdata.readset)) { t_readjunk(tr); } /*----- look for done flushed status ----- */ if (tr->tr_status == TRANSFER_STATUS_WAITING) { t_flushed(tr); } /*----- look for lost transfers ----- */ if (changesec && (tr->tr_status != TRANSFER_STATUS_DONE)) { t_istimeout(tr); } /*----- look for finished transfers ----- */ if (tr->tr_status == TRANSFER_STATUS_DONE) { mydelete(tr->nick); mydelete(tr->caps_nick); mydelete(tr->hostname); tr = irlist_delete(&gdata.trans, tr); if (!gdata.exiting && irlist_size(&gdata.mainqueue) && (irlist_size(&gdata.trans) < min2(MAXTRANS,gdata.slotsmax))) { sendaqueue(0); } } else { tr = irlist_get_next(tr); } } /*----- time for a delayed shutdown? ----- */ if (changesec && gdata.delayedshutdown) { if (!irlist_size(&gdata.trans)) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR, "Delayed Shutdown Activated, No Transfers Remaining"); shutdowniroffer(); } } updatecontext(); /*----- send server stuff ----- */ if (changesec) { sendserver(); if (gdata.curtime%INAMNT_SIZE == (INAMNT_SIZE-1)) gdata.inamnt[0] = 0; else gdata.inamnt[gdata.curtime%INAMNT_SIZE+1] = 0; } /*----- see if we can send out some xdcc lists */ if (changesec && gdata.serverstatus == SERVERSTATUS_CONNECTED) { if (!irlist_size(&gdata.serverq_normal) && !irlist_size(&gdata.serverq_slow)) sendxdlqueue(); } /*----- see if its time to change maxb */ if (changehour) { gdata.maxb = gdata.overallmaxspeed; if (gdata.overallmaxspeeddayspeed != gdata.overallmaxspeed) { struct tm *localt; localt = localtime(&gdata.curtime); if (localt->tm_hour >= gdata.overallmaxspeeddaytimestart && localt->tm_hour < gdata.overallmaxspeeddaytimeend && ( gdata.overallmaxspeeddaydays & (1 << localt->tm_wday)) ) gdata.maxb = gdata.overallmaxspeeddayspeed; } } /*----- see if we've hit a transferlimit or need to reset counters */ if (changesec) { int ii; int transferlimits_over = 0; for (ii=0; iitm_sec = localt->tm_min = localt->tm_hour = 0; /* midnight */ switch (ii) { case TRANSFERLIMIT_DAILY: /* tomorrow */ localt->tm_mday++; break; case TRANSFERLIMIT_WEEKLY: /* next sunday morning */ localt->tm_mday += 7 - localt->tm_wday; break; case TRANSFERLIMIT_MONTHLY: /* next month */ localt->tm_mday = 1; localt->tm_mon++; break; default: outerror(OUTERROR_TYPE_CRASH, "unknown type %d", ii); } /* tm_wday and tm_yday are ignored in mktime() */ gdata.transferlimits[ii].ends = mktime(localt); gdata.transferlimits[ii].used = 0; } if (!transferlimits_over && gdata.transferlimits[ii].limit && (gdata.transferlimits[ii].used >= gdata.transferlimits[ii].limit)) { transferlimits_over = 1; if (!gdata.transferlimits_over) { char *tempstr = mycalloc(maxtextlength); char *tempstr2 = mycalloc(maxtextlength); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR, "All %" LLPRINTFMT "uMB of the %s transfer limit used. Stopping transfers.", gdata.transferlimits[ii].limit / 1024 / 1024, transferlimit_type_to_string(ii)); getdatestr(tempstr2, gdata.transferlimits[ii].ends, maxtextlength); snprintf(tempstr, maxtextlength, "Sorry, I have exceeded my %s transfer limit of %" LLPRINTFMT "uMB. Try again after %s.", transferlimit_type_to_string(ii), gdata.transferlimits[ii].limit / 1024 / 1024, tempstr2); /* remove queued users */ for (pq = irlist_get_head(&gdata.mainqueue); pq; pq = irlist_delete(&gdata.mainqueue, pq)) { notice_slow(pq->nick, tempstr); mydelete(pq->nick); mydelete(pq->hostname); } /* stop transfers */ for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if (tr->tr_status != TRANSFER_STATUS_DONE) { t_closeconn(tr,tempstr,0); } } mydelete(tempstr); mydelete(tempstr2); } } } if (gdata.transferlimits_over != transferlimits_over) { if (!transferlimits_over) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR, "No longer over any transfer limits. Transfers are now allowed."); } gdata.transferlimits_over = transferlimits_over; } } /*----- gdata.autoignore_threshold seconds ----- */ if (changesec && (gdata.curtime - lastignoredec > gdata.autoignore_threshold)) { igninfo *ignore; lastignoredec += gdata.autoignore_threshold; ignore = irlist_get_head(&gdata.ignorelist); while(ignore) { if (!gdata.attop) gototop(); ignore->bucket--; if ((ignore->flags & IGN_IGNORING) && (ignore->bucket < 0)) { ignore->flags &= ~IGN_IGNORING; ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR, "Ignore removed for %s",ignore->hostmask); write_statefile(); } if (ignore->bucket < 0) { if (ignore->regexp) { regfree(ignore->regexp); } mydelete(ignore->regexp); mydelete(ignore->hostmask); ignore = irlist_delete(&gdata.ignorelist, ignore); } else { ignore = irlist_get_next(ignore); } } } /*----- periodicmsg_time seconds ----- */ if (changesec && (gdata.curtime - lastperiodicmsg > gdata.periodicmsg_time*60)) { lastperiodicmsg = gdata.curtime; if (gdata.periodicmsg_nick && gdata.periodicmsg_msg && (gdata.serverstatus == SERVERSTATUS_CONNECTED) ) privmsg(gdata.periodicmsg_nick,"%s",gdata.periodicmsg_msg); } updatecontext(); /*----- 5 seconds ----- */ if (changesec && (gdata.curtime - last5sec > 4)) { last5sec = gdata.curtime; updatecontext(); /*----- server timeout ----- */ if ((gdata.serverstatus == SERVERSTATUS_CONNECTED) && (gdata.curtime - gdata.lastservercontact > SRVRTOUT)) { if (gdata.servertime < 3) { const char *servname = gdata.curserveractualname ? gdata.curserveractualname : gdata.curserver.hostname; int len = 6 + strlen(servname); char *tempstr3 = mycalloc(len + 1); snprintf(tempstr3, len + 1, "PING %s\n", servname); write(gdata.ircserver, tempstr3, len); if (gdata.debug > 0) { tempstr3[len-1] = '\0'; len--; ioutput(CALLTYPE_NORMAL,OUT_S,COLOR_MAGENTA," 3)) { /*----- update lastspeed, check minspeed ----- */ tr = irlist_get_head(&gdata.trans); while(tr) { if ( tr->connecttime+(MIN_TL/2) > gdata.curtime ) /* initial */ { tr->lastspeed = (tr->lastspeed)*DCL_SPDW_I + (((float)(tr->bytessent-tr->lastspeedamt))/1024.0)*(1.0-DCL_SPDW_I)/((float)(gdata.curtime-last4sec)*1.0); } else /* ongoing */ { tr->lastspeed = (tr->lastspeed)*DCL_SPDW_O + (((float)(tr->bytessent-tr->lastspeedamt))/1024.0)*(1.0-DCL_SPDW_O)/((float)(gdata.curtime-last4sec)*1.0); } tr->lastspeedamt = tr->bytessent; t_checkminspeed(tr); tr = irlist_get_next(tr); } ul = irlist_get_head(&gdata.uploads); while(ul) { if ( ul->connecttime+(MIN_TL/2) > gdata.curtime ) /* initial */ { ul->lastspeed = (ul->lastspeed)*DCL_SPDW_I + (((float)(ul->bytesgot-ul->lastspeedamt))/1024.0)*(1.0-DCL_SPDW_I)/((float)(gdata.curtime-last4sec)*1.0); } else /* ongoing */ { ul->lastspeed = (ul->lastspeed)*DCL_SPDW_O + (((float)(ul->bytesgot-ul->lastspeedamt))/1024.0)*(1.0-DCL_SPDW_O)/((float)(gdata.curtime-last4sec)*1.0); } ul->lastspeedamt = ul->bytesgot; ul = irlist_get_next(ul); } last4sec = gdata.curtime; } updatecontext(); /*----- check for size change ----- */ if (changesec) checktermsize(); updatecontext(); /*----- plist stuff ----- */ if ((gdata.serverstatus == SERVERSTATUS_CONNECTED) && changemin && irlist_size(&gdata.xdccs) && !gdata.transferlimits_over && (!gdata.queuesize || irlist_size(&gdata.mainqueue) < gdata.queuesize) && (gdata.nolisting <= gdata.curtime)) { char *tchanf = NULL, *tchanm = NULL, *tchans = NULL; ch = irlist_get_head(&gdata.channels); while(ch) { if ((ch->flags & CHAN_ONCHAN) && ch->plisttime && (((gdata.curtime / 60) % ch->plisttime) == ch->plistoffset)) { if (ch->flags & CHAN_MINIMAL) { if (tchanm) { strncat(tchanm,",",maxtextlength-strlen(tchanm)-1); strncat(tchanm,ch->name,maxtextlength-strlen(tchanm)-1); } else { tchanm = mycalloc(maxtextlength); strncpy(tchanm,ch->name,maxtextlength-1); } } else if (ch->flags & CHAN_SUMMARY) { if (tchans) { strncat(tchans,",",maxtextlength-strlen(tchans)-1); strncat(tchans,ch->name,maxtextlength-strlen(tchans)-1); } else { tchans = mycalloc(maxtextlength); strncpy(tchans,ch->name,maxtextlength-1); } } else { if (tchanf) { strncat(tchanf,",",maxtextlength-strlen(tchanf)-1); strncat(tchanf,ch->name,maxtextlength-strlen(tchanf)-1); } else { tchanf = mycalloc(maxtextlength); strncpy(tchanf,ch->name,maxtextlength-1); } } } ch = irlist_get_next(ch); } if (tchans) { if (gdata.restrictprivlist && !gdata.creditline && !gdata.headline) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_D,COLOR_NO_COLOR,"Can't send Summary Plist to %s (restrictprivlist is set and no creditline or headline, summary makes no sense!)",tchans); } else { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_D,COLOR_NO_COLOR,"Plist sent to %s (summary)",tchans); pubplist = mycalloc(sizeof(userinput)); u_fillwith_msg(pubplist,tchans,"A A A A A xdl"); pubplist->method = method_xdl_channel_sum; u_parseit(pubplist); mydelete(pubplist); } mydelete(tchans); } if (tchanf) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_D,COLOR_NO_COLOR,"Plist sent to %s (full)",tchanf); pubplist = mycalloc(sizeof(userinput)); u_fillwith_msg(pubplist,tchanf,"A A A A A xdl"); pubplist->method = method_xdl_channel; u_parseit(pubplist); mydelete(pubplist); mydelete(tchanf); } if (tchanm) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_D,COLOR_NO_COLOR,"Plist sent to %s (minimal)",tchanm); pubplist = mycalloc(sizeof(userinput)); u_fillwith_msg(pubplist,tchanm,"A A A A A xdl"); pubplist->method = method_xdl_channel_min; u_parseit(pubplist); mydelete(pubplist); mydelete(tchanm); } } updatecontext(); /*----- low bandwidth send, save state file ----- */ if (changesec && (gdata.curtime - last3min > 180)) { last3min = gdata.curtime; xdccsent = 0; for (i=0; i (gdata.notifytime*60))) { lastnotify = gdata.curtime; if (gdata.serverstatus == SERVERSTATUS_CONNECTED) { if ((irlist_size(&gdata.serverq_fast) >= 10) || (irlist_size(&gdata.serverq_normal) >= 10) || (irlist_size(&gdata.serverq_slow) >= 50)) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_D,COLOR_NO_COLOR, "notifications skipped, server queue is rather large"); } else { notifyqueued(); notifybandwidth(); notifybandwidthtrans(); } } } updatecontext(); /*----- log stats / remote admin stats ----- */ if ( gdata.logstats && changesec && gdata.logfile && (gdata.curtime - last2min > 119)) { last2min = gdata.curtime; logstat(); for (chat = irlist_get_head(&gdata.dccchats); chat; chat = irlist_get_next(chat)) { if (chat->status == DCCCHAT_CONNECTED) { writestatus(chat); } } isrotatelog(); } updatecontext(); /*----- 20 seconds ----- */ if (changesec && (gdata.curtime - last20sec > 19)) { if (gdata.logfd != FD_UNUSED) { /* cycle */ close(gdata.logfd); gdata.logfd = FD_UNUSED; } updatecontext(); /* look to see if any files changed */ xd = irlist_get_head(&gdata.xdccs); while(xd) { look_for_file_changes(xd); xd = irlist_get_next(xd); } updatecontext(); /* try rejoining channels not on */ ch = irlist_get_head(&gdata.channels); while(ch) { if ((gdata.serverstatus == SERVERSTATUS_CONNECTED) && !(ch->flags & CHAN_ONCHAN)) { joinchannel(ch); } ch = irlist_get_next(ch); } last20sec = gdata.curtime; updatecontext(); /* try to regain nick */ if (!gdata.user_nick || strcmp(gdata.config_nick,gdata.user_nick)) { writeserver(WRITESERVER_NORMAL, "NICK %s", gdata.config_nick); } updatecontext(); /* update status line */ if (!gdata.background && !gdata.noscreen) { char tempstr[maxtextlength]; char tempstr2[maxtextlengthshort]; if (gdata.attop) gotobot(); tostdout("\x1b[s"); getstatusline(tempstr,maxtextlength); tempstr[min2(maxtextlength-2,gdata.termcols-4)] = '\0'; snprintf(tempstr2,maxtextlengthshort,"\x1b[%d;1H[ %%-%ds ]",gdata.termlines-1,gdata.termcols-4); tostdout(tempstr2,tempstr); tostdout("\x1b[%d;%dH]\x1b[u",gdata.termlines,gdata.termcols); } } updatecontext(); if (changemin) { reverify_restrictsend(); } updatecontext(); if ((gdata.md5build.file_fd != FD_UNUSED) && FD_ISSET(gdata.md5build.file_fd, &gdata.readset)) { ssize_t howmuch; int reads_per_loop = 64; assert(gdata.md5build.xpack); while (reads_per_loop--) { howmuch = read(gdata.md5build.file_fd, gdata.sendbuff, BUFFERSIZE); if (gdata.debug > 4) { if (!gdata.attop) { gototop(); } ioutput(CALLTYPE_NORMAL,OUT_S,COLOR_YELLOW,"[MD5]: read %d",howmuch); } if ((howmuch < 0) && (errno != EAGAIN)) { outerror(OUTERROR_TYPE_WARN,"[MD5]: Can't read data from file '%s': %s", gdata.md5build.xpack->file, strerror(errno)); FD_CLR(gdata.md5build.file_fd, &gdata.readset); close(gdata.md5build.file_fd); gdata.md5build.file_fd = FD_UNUSED; gdata.md5build.xpack = NULL; break; } else if (howmuch < 0) { break; } else if (howmuch == 0) { /* EOF */ MD5Final(gdata.md5build.xpack->md5sum, &gdata.md5build.md5sum); gdata.md5build.xpack->has_md5sum = 1; if (!gdata.attop) { gototop(); } ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "[MD5]: is " MD5_PRINT_FMT, MD5_PRINT_DATA(gdata.md5build.xpack->md5sum)); FD_CLR(gdata.md5build.file_fd, &gdata.readset); close(gdata.md5build.file_fd); gdata.md5build.file_fd = FD_UNUSED; gdata.md5build.xpack = NULL; break; } /* else got data */ MD5Update(&gdata.md5build.md5sum, gdata.sendbuff, howmuch); } } if (!gdata.nomd5sum && changesec && (!gdata.md5build.xpack)) { int packnum = 1; /* see if any pack needs a md5sum calculated */ for (xd = irlist_get_head(&gdata.xdccs); xd; xd = irlist_get_next(xd), packnum++) { if (!xd->has_md5sum) { if (!gdata.attop) { gototop(); } ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "[MD5]: Calculating pack %d",packnum); gdata.md5build.file_fd = open(xd->file, O_RDONLY | ADDED_OPEN_FLAGS); if (gdata.md5build.file_fd >= 0) { gdata.md5build.xpack = xd; MD5Init(&gdata.md5build.md5sum); if (set_socket_nonblocking(gdata.md5build.file_fd, 1) < 0) { outerror(OUTERROR_TYPE_WARN,"[MD5]: Couldn't Set Non-Blocking"); } break; } else { outerror(OUTERROR_TYPE_WARN, "[MD5]: Cant Access Offered File '%s': %s", xd->file, strerror(errno)); gdata.md5build.file_fd = FD_UNUSED; } } } } updatecontext(); if (gdata.exiting && gdata.serverstatus != SERVERSTATUS_CONNECTED) { for (chat = irlist_get_head(&gdata.dccchats); chat; chat = irlist_delete(&gdata.dccchats,chat)) { writedccchat(chat, 0, "iroffer exited, Closing DCC Chat\n"); shutdowndccchat(chat,1); } mylog(CALLTYPE_NORMAL,"iroffer exited\n\n"); tostdout_disable_buffering(1); uninitscreen(); if (gdata.pidfile) unlink(gdata.pidfile); exit(0); } updatecontext(); if (gdata.serverstatus == SERVERSTATUS_NEED_TO_CONNECT) { int timeout; timeout = CTIMEOUT + (gdata.serverconnectbackoff * CBKTIMEOUT); if (gdata.lastservercontact + timeout < gdata.curtime) { if (gdata.debug > 0) { ioutput(CALLTYPE_NORMAL,OUT_S,COLOR_YELLOW,"Reconnecting to server (%d seconds)",timeout); } switchserver(-1); } } if (gdata.needsrehash) { gdata.needsrehash = 0; urehash = mycalloc(sizeof(userinput)); u_fillwith_msg(urehash,NULL,"A A A A A rehash"); urehash->method = method_out_all; /* just OUT_S|OUT_L|OUT_D it */ u_parseit(urehash); mydelete(urehash); } updatecontext(); chat = irlist_get_head(&gdata.dccchats); while (chat) { if (chat->status == DCCCHAT_UNUSED) { chat = irlist_delete(&gdata.dccchats,chat); } else { flushdccchat(chat); chat = irlist_get_next(chat); } } /* END */ updatecontext(); if (gdata.needsclear) drawbot(); if (gdata.attop) gotobot(); changehour=changemin=0; } static void parseline(char *line) { char *part2, *part3, *part4, *part5; char *part3a; char *t; int i; char *tptr; channel_t *ch; updatecontext(); /* we only support lines upto maxtextlength, truncate line */ line[maxtextlength-1] = '\0'; if (gdata.debug > 0) ioutput(CALLTYPE_NORMAL,OUT_S,COLOR_CYAN,">IRC>: %s",line); part2 = getpart(line,2); if (part2 == NULL) { return; } part3 = getpart(line,3); part4 = getpart(line,4); part5 = getpart(line,5); if (part3 && part3[0] == ':') { part3a = part3+1; } else { part3a = part3; } /* NOTICE nick */ if (part3 && gdata.caps_nick && !strcmp(caps(part2),"NOTICE") && !strcmp(caps(part3),gdata.caps_nick)) privmsgparse("NOTICE",line); /* :server 001 xxxx :welcome.... */ if ( !strcmp(part2,"001") ) { ioutput(CALLTYPE_NORMAL,OUT_S,COLOR_NO_COLOR,"Server welcome: %s",line); /* update server name */ mydelete(gdata.curserveractualname); gdata.curserveractualname = getpart(line+1,1); /* update nick */ mydelete(gdata.user_nick); mydelete(gdata.caps_nick); gdata.user_nick = mymalloc(strlen(part3)+1); gdata.caps_nick = mymalloc(strlen(part3)+1); strcpy(gdata.user_nick,part3); strcpy(gdata.caps_nick,part3); caps(gdata.caps_nick); gdata.nick_number = 0; gdata.needsclear = 1; if (gdata.user_modes && strlen(gdata.user_modes)) { writeserver(WRITESERVER_NOW, "MODE %s %s", gdata.user_nick, gdata.user_modes); } /* server connected raw command */ tptr = irlist_get_head(&gdata.server_connected_raw); while(tptr) { writeserver(WRITESERVER_NORMAL, "%s", tptr); tptr = irlist_get_next(tptr); } /* nickserv */ if (gdata.nickserv_pass) { privmsg("nickserv","IDENTIFY %s",gdata.nickserv_pass); } } /* :server 005 xxxx aaa bbb=x ccc=y :are supported... */ if ( !strcmp(part2,"005") ) { int ii = 4; char *item; while((item = getpart(line, ii++))) { if (item[0] == ':') { mydelete(item); break; } if (!strncmp("PREFIX=(", item, 8)) { char *ptr = item+8; int pi; memset(&gdata.prefixes, 0, sizeof(gdata.prefixes)); for (pi = 0; (ptr[pi] && (ptr[pi] != ')') && (pi < MAX_PREFIX)); pi++) { gdata.prefixes[pi].p_mode = ptr[pi]; } if (ptr[pi] == ')') { ptr += pi + 1; for (pi = 0; (ptr[pi] && (pi < MAX_PREFIX)); pi++) { gdata.prefixes[pi].p_symbol = ptr[pi]; } } for (pi = 0; pi < MAX_PREFIX; pi++) { if ((gdata.prefixes[pi].p_mode && !gdata.prefixes[pi].p_symbol) || (!gdata.prefixes[pi].p_mode && gdata.prefixes[pi].p_symbol)) { outerror(OUTERROR_TYPE_WARN, "Server prefix list doesn't make sense, using defaults: %s", item); initprefixes(); } } } if (!strncmp("CHANMODES=", item, 10)) { char *ptr = item+10; int ci; int cm; memset(&gdata.chanmodes, 0, sizeof(gdata.chanmodes)); for (ci = cm = 0; (ptr[ci] && (cm < MAX_CHANMODES)); ci++) { if (ptr[ci+1] == ',') { /* we only care about ones with arguments */ gdata.chanmodes[cm++] = ptr[ci++]; } } } mydelete(item); } } /* :server 433 old new :Nickname is already in use. */ if ( !strcmp(part2,"433") && part3 && !strcmp(part3,"*") && part4 ) { ioutput(CALLTYPE_NORMAL, OUT_S, COLOR_NO_COLOR, "Nickname %s already in use, trying %s%d", part4, gdata.config_nick, gdata.nick_number); /* generate new nick and retry */ writeserver(WRITESERVER_NORMAL, "NICK %s%d", gdata.config_nick, gdata.nick_number++); } /* names list for a channel */ /* :server 353 our_nick = #channel :nick @nick +nick nick */ if ( !strcmp(part2,"353") && part3 && part4 && part5 ) { caps(part5); ch = irlist_get_head(&gdata.channels); while(ch) { if (!strcmp(part5,ch->name)) { break; } ch = irlist_get_next(ch); } if (!ch) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR, "Got name data for %s which is not a known channel!",part5); } else { for (i=0; (t = getpart(line,6+i)); i++) { addtomemberlist(ch, i == 0 ? t+1 : t); mydelete(t); } } } /* ERROR :Closing Link */ if (strncmp(line, "ERROR :Closing Link", strlen("ERROR :Closing Link")) == 0) { if (gdata.exiting) gdata.recentsent = 0; else { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_RED,"Server Closed Connection: %s",line); FD_CLR(gdata.ircserver, &gdata.readset); /* * cygwin close() is broke, if outstanding data is present * it will block until the TCP connection is dead, sometimes * upto 10-20 minutes, calling shutdown() first seems to help */ shutdown(gdata.ircserver, SHUT_RDWR); close(gdata.ircserver); gdata.serverstatus = SERVERSTATUS_NEED_TO_CONNECT; } } /* server ping */ if (PING_SRVR && (strncmp(line, "PING :", 6) == 0)) { if (gdata.debug > 0) ioutput(CALLTYPE_NORMAL,OUT_S,COLOR_NO_COLOR,"Server Ping: %s",line); writeserver(WRITESERVER_NOW, "PO%s", line+2); } /* JOIN */ if (!strcmp(part2,"JOIN") && part3a && gdata.caps_nick) { char* nick; int j,found; nick = mycalloc(strlen(line)+1); j=1; gdata.nocon = 0; found = 0; while(line[j] != '!' && jname)) { ch->flags |= CHAN_ONCHAN; break; } ch = irlist_get_next(ch); } if (!ch) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR,"%s is not a known channel!",part3a); } } else { /* someone else joined */ caps(part3a); ch = irlist_get_head(&gdata.channels); while(ch) { if (!strcmp(part3a,ch->name)) { break; } ch = irlist_get_next(ch); } if (!ch) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR,"%s is not a known channel!",part3a); } else { addtomemberlist(ch,nick); } } mydelete(nick); } /* PART */ if (!strcmp(part2,"PART") && part3a && gdata.caps_nick) { char* nick; int j; nick = mycalloc(strlen(line)+1); j=1; while(line[j] != '!' && jname)) { break; } ch = irlist_get_next(ch); } if (!ch) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR,"%s is not a known channel!",part3a); } else { removefrommemberlist(ch,nick); } reverify_restrictsend(); } mydelete(nick); } /* QUIT */ if (!strcmp(part2,"QUIT") && gdata.caps_nick) { char* nick; int j; nick = mycalloc(strlen(line)+1); j=1; while(line[j] != '!' && jname)) { if(!strcmp(caps(part4),gdata.caps_nick)) { /* we were kicked */ ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR,"Kicked, Rejoining: %s",line); joinchannel(ch); ch->flags &= ~CHAN_ONCHAN; } else { /* someone else was kicked */ removefrommemberlist(ch,part4); } } ch = irlist_get_next(ch); } reverify_restrictsend(); } /* MODE #channel +x ... */ if (!strcmp(part2,"MODE") && part3 && part4) { /* find channel */ for (ch = irlist_get_head(&gdata.channels); ch; ch = irlist_get_next(ch)) { if (!strcasecmp(ch->name, part3)) { break; } } if (ch) { int plus = 0; int part = 5; char *ptr; for (ptr = part4; *ptr; ptr++) { if (*ptr == '+') { plus = 1; } else if (*ptr == '-') { plus = 0; } else { int ii; for (ii = 0; (ii < MAX_PREFIX && gdata.prefixes[ii].p_mode); ii++) { if (*ptr == gdata.prefixes[ii].p_mode) { /* found a nick mode */ char *nick = getpart(line, part++); if (nick) { if (nick[strlen(nick)-1] == '\1') { nick[strlen(nick)-1] == '\0'; } changeinmemberlist_mode(ch, nick, gdata.prefixes[ii].p_symbol, plus); mydelete(nick); } break; } } for (ii = 0; (ii < MAX_CHANMODES && gdata.chanmodes[ii]); ii++) { if (*ptr == gdata.chanmodes[ii]) { /* found a channel mode that has an argument */ part++; break; } } } } } } /* PRIVMSG */ if (!strcmp(part2,"PRIVMSG")) { if (gdata.autosend.word && part4 && !strcmp(caps(part4+1),caps(gdata.autosend.word))) { autosendf(line); } else { privmsgparse("PRIVMSG",line); } } mydelete(part2); mydelete(part3); mydelete(part4); mydelete(part5); } static void privmsgparse(const char* type, char* line) { char *nick, *hostname, *hostmask, *wildhost; char *msg1, *msg2, *msg3, *msg4, *msg5, *msg6, *dest; int i,j,k; userinput ui; igninfo *ignore = NULL; upload *ul; transfer *tr; pqueue *pq; xdcc *xd; int line_len; updatecontext(); floodchk(); line_len = sstrlen(line); hostmask = caps(getpart(line,1)); for (i=1; i<=sstrlen(hostmask); i++) hostmask[i-1] = hostmask[i]; dest = caps(getpart(line,3)); msg1 = getpart(line,4); msg2 = getpart(line,5); msg3 = getpart(line,6); msg4 = getpart(line,7); msg5 = getpart(line,8); msg6 = getpart(line,9); if (msg1) msg1++; /* point past the ":" */ nick = mycalloc(line_len+1); hostname = mycalloc(line_len+1); wildhost = mycalloc(line_len+2); i=1; j=0; while(line[i] != '!' && iregexp != NULL) && !regexec(ignore->regexp,hostmask,0,NULL,0)) { /* already in list */ j=1; ignore->bucket++; ignore->lastcontact = gdata.curtime; if (!(ignore->flags & IGN_IGNORING) && (ignore->bucket >= IGN_ON)) { int left; left = gdata.autoignore_threshold*(ignore->bucket+1); ignore->flags |= IGN_IGNORING; ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR, "Auto-ignore activated for %s (%s) lasting %i%c%i%c", nick, wildhost, left < 3600 ? left/60 : left/60/60 , left < 3600 ? 'm' : 'h', left < 3600 ? left%60 : (left/60)%60 , left < 3600 ? 's' : 'm'); notice(nick, "Auto-ignore activated for %s (%s) lasting %i%c%i%c. Further messages will increase duration.", nick, wildhost, left < 3600 ? left/60 : left/60/60 , left < 3600 ? 'm' : 'h', left < 3600 ? left%60 : (left/60)%60 , left < 3600 ? 's' : 'm'); write_statefile(); } if (ignore->flags & IGN_IGNORING) { goto privmsgparse_cleanup; } break; } ignore = irlist_get_next(ignore); } if (!ignore) { char *tempr; /* not in list */ ignore = irlist_add(&gdata.ignorelist,sizeof(igninfo)); ignore->regexp = mycalloc(sizeof(regex_t)); ignore->hostmask = mymalloc(strlen(wildhost)+1); strcpy(ignore->hostmask,wildhost); tempr = hostmasktoregex(wildhost); if (regcomp(ignore->regexp,tempr,REG_ICASE|REG_NOSUB)) { ignore->regexp = NULL; } ignore->bucket = 1; ignore->flags &= ~IGN_MANUAL & ~IGN_IGNORING; ignore->lastcontact = gdata.curtime; mydelete(tempr); } } noignore: /*----- CLIENTINFO ----- */ if ( !gdata.ignore && (!strcmp(msg1,"\1CLIENTINFO") || !strcmp(msg1,"\1CLIENTINFO\1") )) { gdata.inamnt[gdata.curtime%INAMNT_SIZE]++; if (!msg2) { notice(nick,"\1CLIENTINFO DCC PING VERSION XDCC UPTIME " ":Use CTCP CLIENTINFO to get more specific information\1"); } else if (strncmp(caps(msg2),"PING",4) == 0) notice(nick,"\1CLIENTINFO PING returns the arguments it receives\1"); else if (strncmp(caps(msg2),"DCC",3) == 0) notice(nick,"\1CLIENTINFO DCC requests a DCC for chatting or file transfer\1"); else if (strncmp(caps(msg2),"VERSION",7) == 0) notice(nick,"\1CLIENTINFO VERSION shows information about this client's version\1"); else if (strncmp(caps(msg2),"XDCC",4) == 0) notice(nick,"\1CLIENTINFO XDCC LIST|SEND list and DCC file(s) to you\1"); else if (strncmp(caps(msg2),"UPTIME",6) == 0) notice(nick,"\1CLIENTINFO UPTIME shows how long this client has been running\1"); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"[CTCP] %s: CLIENTINFO",nick); } /*----- PING ----- */ else if ( !gdata.ignore && (!strcmp(msg1,"\1PING") || !strcmp(msg1,"\1PING\1") )) { gdata.inamnt[gdata.curtime%INAMNT_SIZE]++; if (msg2 && (msg2[strlen(msg2)-1] == '\1')) { msg2[strlen(msg2)-1] = '\0'; } if (msg3 && (msg3[strlen(msg3)-1] == '\1')) { msg3[strlen(msg3)-1] = '\0'; } notice(nick, "\1PING%s%s%s%s\1", msg2 ? " " : "", msg2 ? msg2 : "", msg3 ? " " : "", msg3 ? msg3 : ""); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"[CTCP] %s: PING",nick); } /*----- VERSION ----- */ else if ( !gdata.ignore && (!strcmp(msg1,"\1VERSION") || !strcmp(msg1,"\1VERSION\1") )) { gdata.inamnt[gdata.curtime%INAMNT_SIZE]++; notice(nick,"\1VERSION iroffer v" VERSIONLONG ", http://iroffer.org/%s%s\1", gdata.hideos ? "" : " - ", gdata.hideos ? "" : gdata.osstring); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"[CTCP] %s: VERSION",nick); } /*----- UPTIME ----- */ else if ( !gdata.ignore && (!strcmp(msg1,"\1UPTIME") || !strcmp(msg1,"\1UPTIME\1") )) { char *tempstr2 = mycalloc(maxtextlength); gdata.inamnt[gdata.curtime%INAMNT_SIZE]++; tempstr2 = getuptime(tempstr2, 0, gdata.startuptime, maxtextlength); notice(nick,"\1UPTIME %s\1", tempstr2); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"[CTCP] %s: UPTIME",nick); mydelete(tempstr2); } /*----- STATUS ----- */ else if ( !gdata.ignore && (!strcmp(msg1,"\1STATUS") || !strcmp(msg1,"\1STATUS\1") )) { char *tempstr2 = mycalloc(maxtextlength); gdata.inamnt[gdata.curtime%INAMNT_SIZE]++; tempstr2 = getstatuslinenums(tempstr2,maxtextlength); notice(nick,"\1%s\1",tempstr2); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"[CTCP] %s: STATUS",nick); mydelete(tempstr2); } /*----- DCC SEND/CHAT/RESUME ----- */ else if ( !gdata.ignore && gdata.caps_nick && !strcmp(gdata.caps_nick,dest) && !strcmp(caps(msg1),"\1DCC") && msg2) { if (!gdata.attop) gototop(); if (!strcmp(caps(msg2),"RESUME") && msg3 && msg4 && msg5) { gdata.inamnt[gdata.curtime%INAMNT_SIZE]++; caps(nick); if (msg5[strlen(msg5)-1] == '\1') msg5[strlen(msg5)-1] = '\0'; tr = irlist_get_head(&gdata.trans); while(tr) { if ((tr->tr_status == TRANSFER_STATUS_LISTENING) && !strcmp(tr->caps_nick,nick) && (strstrnocase(tr->xpack->file,msg3) || (tr->listenport == atoi(msg4)))) { if (atoull(msg5) >= (unsigned long long)tr->xpack->st_size) { notice(nick,"You can't resume the transfer at a point greater than the size of the file"); ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_YELLOW, "XDCC [%02i:%s]: Resume attempted beyond end of file ( %" LLPRINTFMT "u >= %" LLPRINTFMT "u )", tr->id, tr->nick, atoull(msg5), (unsigned long long)tr->xpack->st_size); } else { t_setresume(tr,msg5); privmsg_fast(nick,"\1DCC ACCEPT %s %s %s\1",msg3,msg4,msg5); ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_YELLOW, "XDCC [%02i:%s]: Resumed at %" LLPRINTFMT "iK", tr->id, tr->nick, (long long)(tr->startresume / 1024)); } break; } tr = irlist_get_next(tr); } if (!tr) { outerror(OUTERROR_TYPE_WARN,"Couldn't find transfer that %s tried to resume!",nick); tr = irlist_get_head(&gdata.trans); while(tr) { if (gdata.debug > 0) { ioutput(CALLTYPE_NORMAL,OUT_S,COLOR_NO_COLOR, "resume trying %i: %s == %s, %s == %s, %i == %i\n", tr->tr_status, tr->caps_nick,nick, tr->xpack->file,msg3, tr->listenport,atoi(msg4)); } tr = irlist_get_next(tr); } } } else if (!strcmp(caps(msg2), "CHAT")) { if ( verifyhost(&gdata.adminhost, hostmask) ) { ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_MAGENTA, "DCC CHAT attempt authorized from %s", hostmask); setupdccchat(nick, line); } else { notice(nick,"DCC Chat denied from %s",hostmask); ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_MAGENTA, "DCC CHAT attempt denied from %s", hostmask); } } else if (!strcmp(caps(msg2), "SEND") && msg3 && msg4 && msg5 && msg6) { if (msg6[strlen(msg6)-1] == '\1') { msg6[strlen(msg6)-1] = '\0'; } if ( !verifyhost(&gdata.uploadhost, hostmask) ) { notice(nick,"DCC Send Denied, I don't accept transfers from %s", hostmask); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_MAGENTA, "DCC Send Denied from %s",hostmask); } else if ( gdata.uploadmaxsize && atoull(msg6) > gdata.uploadmaxsize) { notice(nick,"DCC Send Denied, I don't accept transfers that big"); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_MAGENTA, "DCC Send Denied (Too Big) from %s",hostmask); } else if ( atoull(msg6) > gdata.max_file_size) { notice(nick,"DCC Send Denied, I can't accept transfers that large"); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_MAGENTA, "DCC Send Denied (Too Large) from %s",hostmask); } else if (irlist_size(&gdata.uploads) >= MAXUPLDS) { notice(nick,"DCC Send Denied, I'm already getting too many files"); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_MAGENTA, "DCC Send Denied (too many uploads) from %s",hostmask); } else { ul = irlist_add(&gdata.uploads, sizeof(upload)); l_initvalues(ul); removenonprintablefile(msg3); ul->file = mymalloc(strlen(msg3)+1); strcpy(ul->file,msg3); ul->remoteip = atoul(msg4); ul->remoteport = atoi(msg5); ul->totalsize = (off_t)atoull(msg6); ul->nick = mymalloc(strlen(nick)+1); strcpy(ul->nick,nick); ul->hostname = mymalloc(strlen(hostname)+1); strcpy(ul->hostname,hostname); ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_YELLOW, "DCC Send Accepted from %s: %s (%" LLPRINTFMT "iKB)", nick, ul->file, (long long)(ul->totalsize / 1024)); l_establishcon(ul); } } else if (!strcmp(caps(msg2), "ACCEPT") && msg3 && msg4 && msg5) { if (msg5[strlen(msg5)-1] == '\1') { msg5[strlen(msg5)-1] = '\0'; } if ( !verifyhost(&gdata.uploadhost, hostmask) ) { notice(nick,"DCC Send Denied, I don't accept transfers from %s", hostmask); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_MAGENTA, "DCC Send Denied from %s",hostmask); } else if ( gdata.uploadmaxsize && atoull(msg5) > gdata.uploadmaxsize) { notice(nick,"DCC Send Denied, I don't accept transfers that big"); ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_MAGENTA, "DCC Send denied from %s (too big)", hostmask); } else if ( atoull(msg5) > gdata.max_file_size) { notice(nick,"DCC Send Denied, I can't accept transfers that large"); ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_MAGENTA, "DCC Send denied from %s (too large)", hostmask); } ul = irlist_get_head(&gdata.uploads); while (ul) { if ((ul->remoteport == atoi(msg4)) && !strcmp(ul->nick, nick)) { ul->resumed = 1; ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"DCC Send Resumed from %s: %s (%" LLPRINTFMT "i of %" LLPRINTFMT "iKB left)", nick, ul->file, (long long)((ul->totalsize - ul->resumesize) / 1024), (long long)(ul->totalsize / 1024)); l_establishcon(ul); break; } ul = irlist_get_next(ul); } if (!ul) { notice(nick, "DCC Resume Denied, unable to find transfer"); outerror(OUTERROR_TYPE_WARN, "Couldn't find upload that %s tried to resume!", nick); } } } /*----- ADMIN ----- */ else if ( !gdata.ignore && gdata.caps_nick && !strcmp(gdata.caps_nick,dest) && !strcmp(caps(msg1),"ADMIN") ) { /* msg2 = getpart(line,5); */ if (!gdata.attop) gototop(); if ( verifyhost(&gdata.adminhost, hostmask) ) { if ( verifypass(msg2) ) { if (line[line_len-1] == '\n') { line[line_len-1] = '\0'; line_len--; } u_fillwith_msg(&ui,nick,line); u_parseit(&ui); /* admin commands shouldn't count against ignore */ if (ignore) { ignore->bucket--; } } else { notice(nick,"ADMIN: Incorrect Password"); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_MAGENTA,"Incorrect ADMIN Password (%s)",hostmask); } } else { notice(nick,"ADMIN: %s is not allowed to issue admin commands",hostmask); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_MAGENTA,"Incorrect ADMIN Hostname (%s)",hostmask); } } /*----- XDCC ----- */ else if ( !gdata.ignore && gdata.caps_nick && (!strcmp(gdata.caps_nick,dest) || gdata.respondtochannelxdcc) && (!strcmp(caps(msg1),"XDCC") || !strcmp(msg1,"\1XDCC") || !strcmp(caps(msg1),"CDCC") || !strcmp(msg1,"\1CDCC") )) { gdata.inamnt[gdata.curtime%INAMNT_SIZE]++; caps(msg2); if (msg3 && msg3[strlen(msg3)-1] == '\1') msg3[strlen(msg3)-1] = '\0'; if ( msg2 && ( !strcmp(msg2,"LIST") || !strcmp(msg2,"LIST\1"))) { if (!gdata.attop) gototop(); if (gdata.restrictprivlist) { j = 2; /* deny */ if (gdata.restrictprivlistmsg) { notice(nick,"XDCC LIST Denied. %s", gdata.restrictprivlistmsg); } else { notice(nick,"XDCC LIST Denied. Wait for the public list in the channel."); } } else if (gdata.restrictlist && (!isinmemberlist(nick))) { j = 2; /* deny */ notice(nick,"XDCC LIST Denied. You must be on a known channel to request a list"); } else { char *user; user = irlist_get_head(&gdata.xlistqueue); while (user) { if (!strcmp(user,nick)) { break; } user = irlist_get_next(user); } if (!user) { if (irlist_size(&gdata.xlistqueue) >= MAXXLQUE) { j = 2; /* deny */ notice_slow(nick,"XDCC LIST Denied. I'm rather busy at the moment, try again later"); } else { user = irlist_add(&gdata.xlistqueue, strlen(nick) + 1); strcpy(user,nick); } } } ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"XDCC LIST %s: (%s)",(j==1?"ignored":(j==2?"denied":"queued")),hostmask); } else if (gdata.caps_nick && !strcmp(gdata.caps_nick,dest)) { if ( msg2 && msg3 && (!strcmp(msg2,"SEND") || !strcmp(msg2,"GET"))) { if (!gdata.attop) gototop(); ioutput(CALLTYPE_MULTI_FIRST,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"XDCC SEND %s",msg3); sendxdccfile(nick, hostname, hostmask, packnumtonum(msg3), NULL); } else if ( msg2 && msg3 && (!strcmp(msg2,"INFO"))) { if (!gdata.attop) gototop(); ioutput(CALLTYPE_MULTI_FIRST,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"XDCC INFO %s",msg3); sendxdccinfo(nick, hostname, hostmask, packnumtonum(msg3), NULL); } else if ( msg2 && !strcmp(msg2,"REMOVE")) { if (!gdata.attop) gototop(); k=0; pq = irlist_get_head(&gdata.mainqueue); while (pq) { if (!strcmp(pq->nick,nick)) { notice(nick, "Removed you from the queue for \"%s\", you waited %li minute%s.", pq->xpack->desc, (long)(gdata.curtime-pq->queuedtime)/60, ((gdata.curtime-pq->queuedtime)/60) != 1 ? "s" : ""); mydelete(pq->nick); mydelete(pq->hostname); pq = irlist_delete(&gdata.mainqueue, pq); k=1; } else { pq = irlist_get_next(pq); } } if (!k) notice(nick,"You Don't Appear To Be In A Queue"); ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"XDCC REMOVE (%s) ",hostmask); } else if ( msg2 && !strcmp(msg2,"SEARCH") && msg3) { if (!gdata.attop) gototop(); notice_slow(nick,"Searching for \"%s\"...",msg3); i = 1; k = 0; xd = irlist_get_head(&gdata.xdccs); while(xd) { if (strstrnocase(xd->file,msg3) || strstrnocase(xd->desc,msg3) || strstrnocase(xd->note,msg3)) { notice_slow(nick," - Pack #%i matches, \"%s\"", i, xd->desc); k++; } i++; xd = irlist_get_next(xd); } if (!k) { notice_slow(nick,"Sorry, nothing was found, try a XDCC LIST"); } ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"XDCC SEARCH %s (%s)",msg3,hostmask); } } } /*----- !LIST ----- */ else if ( !gdata.ignore && gdata.caps_nick && gdata.respondtochannellist && msg1 && !strcasecmp(caps(msg1),"!LIST") && ( !msg2 || !strcmp(caps(msg2),gdata.caps_nick) )) { gdata.inamnt[gdata.curtime%INAMNT_SIZE]++; /* generate !list styled message */ notice_slow(nick, "\2(\2XDCC\2)\2 Packs:\2(\2%d\2)\2 " "Trigger:\2(\2/msg %s xdcc list\2)\2 " "Sends:\2(\2%i/%i\2)\2 " "Queues:\2(\2%i/%i\2)\2 " "Record:\2(\2%1.1fKB/s\2)\2 " "%s%s%s\2=\2iroffer\2=\2", irlist_size(&gdata.xdccs), (gdata.user_nick ? gdata.user_nick : "??"), irlist_size(&gdata.trans),gdata.slotsmax, irlist_size(&gdata.mainqueue),gdata.queuesize, gdata.record, gdata.creditline ? "Note:\2(\2" : "", gdata.creditline ? gdata.creditline : "", gdata.creditline ? "\2)\2 " : ""); } else { if (dest && gdata.caps_nick && !strcmp(dest,gdata.caps_nick)) { if ((gdata.lognotices && !strcmp(type,"NOTICE")) || (gdata.logmessages && !strcmp(type,"PRIVMSG"))) { msglog_t *ml; char *begin; ioutput(CALLTYPE_NORMAL,OUT_S|OUT_D,COLOR_GREEN,"%s from %s logged, use MSGREAD to display it.",type,nick); ml = irlist_add(&gdata.msglog, sizeof(msglog_t)); begin = line + 5 + strlen(hostmask) + strlen(type) + strlen(dest); ml->when = gdata.curtime; ml->hostmask = mymalloc(strlen(hostmask)+1); strcpy(ml->hostmask, hostmask); ml->message = mymalloc(strlen(begin)+1); strcpy(ml->message, begin); write_statefile(); } else { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_GREEN,"%s: %s",type,line); } } } privmsgparse_cleanup: if (msg1) msg1--; mydelete(dest); mydelete(nick); mydelete(hostname); mydelete(hostmask); mydelete(wildhost); mydelete(msg1); mydelete(msg2); mydelete(msg3); mydelete(msg4); mydelete(msg5); mydelete(msg6); return; } static void autosendf(char* line) { char *nick, *hostname, *hostmask; int i,j; updatecontext(); floodchk(); nick = mycalloc(maxtextlengthshort); hostname = mycalloc(maxtextlength); hostmask = caps(getpart(line,1)); for (i=1; i<=sstrlen(hostmask); i++) hostmask[i-1] = hostmask[i]; i=1; j=0; while(line[i] != '!' && i irlist_size(&gdata.xdccs)) || (pack < 1)) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," (Bad Pack Number): "); notice(nick,"** Invalid Pack Number, Try Again"); goto done; } xd = irlist_get_nth(&gdata.xdccs, pack-1); tr = irlist_get_head(&gdata.trans); while(tr) { if (!man && !strcmp(tr->hostname,hostname)) { usertrans++; if (xd == tr->xpack) { userpackok = 0; } } tr = irlist_get_next(tr); } if (!man && usertrans && !userpackok) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," Denied (dup): "); notice(nick,"** You already requested that pack"); } else if (!man && gdata.nonewcons > gdata.curtime ) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," (No New Cons): "); notice(nick,"** The Owner Has Requested That No New Connections Are Made In The Next %li Minute%s",(gdata.nonewcons-gdata.curtime+1)/60,((gdata.nonewcons-gdata.curtime+1)/60)!=1?"s":""); } else if (!man && gdata.transferlimits_over) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," (Over Transfer Limit): "); notice(nick,"** Sorry, I have exceeded my transfer limit for today. Try again tomorrow."); } /* if maxtransfersperperson is reached, queue the file, unless queues are used up, which is checked in addtoqueue() */ else if ( !man && usertrans >= gdata.maxtransfersperperson) { char *tempstr; tempstr = addtoqueue(nick, hostname, pack); notice(nick, "** You can only have %d transfer%s at a time, %s", gdata.maxtransfersperperson, gdata.maxtransfersperperson!=1?"s":"", tempstr); mydelete(tempstr); } else if ((irlist_size(&gdata.trans) >= MAXTRANS) || (!man && (((xd->st_size < gdata.smallfilebypass) && (gdata.slotsmax >= MAXTRANS)) || ((xd->st_size >= gdata.smallfilebypass) && (gdata.slotsmax-irlist_size(&gdata.trans) <= 0))))) { char *tempstr; tempstr = addtoqueue(nick, hostname, pack); notice(nick, "** All Slots Full, %s", tempstr); mydelete(tempstr); } else { char *sizestrstr; char *sendnamestr; look_for_file_changes(xd); xd->file_fd_count++; tr = irlist_add(&gdata.trans, sizeof(transfer)); t_initvalues(tr); tr->id = get_next_tr_id(); tr->nick = mymalloc(strlen(nick)+1); strcpy(tr->nick,nick); tr->caps_nick = mymalloc(strlen(nick)+1); strcpy(tr->caps_nick,nick); caps(tr->caps_nick); tr->hostname = mymalloc(strlen(hostname)+1); strcpy(tr->hostname,hostname); tr->xpack = xd; if (!man) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," requested: "); } if (!gdata.quietmode) { sizestrstr = sizestr(0, tr->xpack->st_size); if (!msg) { notice_fast(nick,"** Sending you pack #%i (\"%s\"), which is %sB (resume supported)", pack, tr->xpack->desc, sizestrstr); } else { writeserver(WRITESERVER_FAST, "NOTICE %s%s Which Is %sB. (Resume Supported)", nick, msg, sizestrstr); } mydelete(sizestrstr); } t_setuplisten(tr); if (tr->tr_status == TRANSFER_STATUS_LISTENING) { sendnamestr = getsendname(tr->xpack->file); privmsg_fast(nick,"\1DCC SEND %s %lu %i %" LLPRINTFMT "u\1", sendnamestr, gdata.ourip, tr->listenport, (unsigned long long)tr->xpack->st_size); mydelete(sendnamestr); } } done: if (!man) ioutput(CALLTYPE_MULTI_END,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"%s (%s)",nick,hostname); } void sendxdccinfo(const char* nick, const char* hostname, const char* hostmask, int pack, const char* msg) { xdcc *xd; char *sizestrstr; char *sendnamestr; char tempstr[maxtextlengthshort]; updatecontext(); if (!verifyhost(&gdata.downloadhost, hostmask)) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," Denied (host denied): "); notice(nick,"** XDCC INFO denied, I don't send transfers to %s", hostmask); goto done; } else if (gdata.restrictsend && !isinmemberlist(nick)) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," Denied (restricted): "); notice(nick,"** XDCC INFO denied, you must be on a known channel to request pack info"); goto done; } else if ((pack > irlist_size(&gdata.xdccs)) || (pack < 1)) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," (Bad Pack Number): "); notice(nick,"** Invalid Pack Number, Try Again"); goto done; } xd = irlist_get_nth(&gdata.xdccs, pack-1); ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," requested: "); notice_slow(nick, "Pack Info for Pack #%i:", pack); sendnamestr = getsendname(xd->file); notice_slow(nick, " Filename %s", sendnamestr); if (strcmp(sendnamestr, xd->desc)) { notice_slow(nick, " Description %s", xd->desc); } mydelete(sendnamestr); if (xd->note[0]) { notice_slow(nick, " Note %s", xd->note); } sizestrstr = sizestr(1, xd->st_size); notice_slow(nick, " Filesize %" LLPRINTFMT "i [%sB]", (long long)xd->st_size, sizestrstr); mydelete(sizestrstr); getdatestr(tempstr, xd->mtime, maxtextlengthshort); notice_slow(nick, " Last Modified %s", tempstr); notice_slow(nick, " Gets %d", xd->gets); if (xd->minspeed) { notice_slow(nick, " Minspeed %1.1fKB/sec", xd->minspeed); } if (xd->maxspeed) { notice_slow(nick, " Maxspeed %1.1fKB/sec", xd->maxspeed); } if (xd->has_md5sum) { notice_slow(nick, " md5sum " MD5_PRINT_FMT, MD5_PRINT_DATA(xd->md5sum)); } done: ioutput(CALLTYPE_MULTI_END,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,"%s (%s)",nick,hostname); return; } static char* addtoqueue(const char* nick, const char* hostname, int pack) { char *tempstr = mycalloc(maxtextlength); pqueue *tempq; xdcc *tempx; int inq,alreadytrans; pqueue *pq; updatecontext(); tempx = irlist_get_nth(&gdata.xdccs, pack-1); alreadytrans = inq = 0; pq = irlist_get_head(&gdata.mainqueue); while(pq) { if (!strcmp(pq->hostname,hostname)) { inq++; if (pq->xpack == tempx) { alreadytrans++; } } pq = irlist_get_next(pq); } if (alreadytrans) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," Denied (queue/dup): "); snprintf(tempstr, maxtextlength, "Denied, You already have that item queued."); return tempstr; } if (inq >= gdata.maxqueueditemsperperson) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," Denied (user/queue): "); snprintf(tempstr, maxtextlength, "Denied, You already have %i items queued, Try Again Later", inq); return tempstr; } if (irlist_size(&gdata.mainqueue) >= gdata.queuesize) { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," Denied (slot/queue): "); snprintf(tempstr, maxtextlength, "Main queue of size %d is Full, Try Again Later", gdata.queuesize); } else { ioutput(CALLTYPE_MULTI_MIDDLE,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," Queued (slot): "); tempq = irlist_add(&gdata.mainqueue, sizeof(pqueue)); tempq->queuedtime = gdata.curtime; tempq->nick = mymalloc(strlen(nick)+1); strcpy(tempq->nick,nick); tempq->hostname = mymalloc(strlen(hostname)+1); strcpy(tempq->hostname,hostname); tempq->xpack = tempx; snprintf(tempstr,maxtextlength, "Added you to the main queue in position %d. To Remove youself at " "a later time type \"/msg %s xdcc remove\".", irlist_size(&gdata.mainqueue), (gdata.user_nick ? gdata.user_nick : "??")); } return tempstr; } void sendaqueue(int type) { int usertrans; pqueue *pq; transfer *tr; char *sendnamestr; updatecontext(); if (!gdata.attop) gototop(); if (irlist_size(&gdata.mainqueue)) { /* * first determine what the first queue position is that is eligable * for a transfer find the first person who has not already maxed out * his sends if noone, do nothing and let execution continue to pack * queue check */ pq = irlist_get_head(&gdata.mainqueue); if (type != 2) { while (pq) { usertrans=0; tr = irlist_get_head(&gdata.trans); while(tr) { if (!strcmp(tr->hostname,pq->hostname)) { usertrans++; } tr = irlist_get_next(tr); } /* usertrans is the number of transfers a user has in progress */ if (usertrans < gdata.maxtransfersperperson) { break; /* found the person that will get the send */ } pq = irlist_get_next(pq); } } if (!pq) { return; } if (type == 1) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW, "QUEUED SEND (low bandwidth): %s (%s)", pq->nick, pq->hostname); } else if (type == 2) { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW, "QUEUED SEND (manual): %s (%s)", pq->nick, pq->hostname); } else { ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW, "QUEUED SEND: %s (%s)", pq->nick, pq->hostname); } look_for_file_changes(pq->xpack); pq->xpack->file_fd_count++; tr = irlist_add(&gdata.trans, sizeof(transfer)); t_initvalues(tr); tr->id = get_next_tr_id(); tr->nick = mymalloc(strlen(pq->nick)+1); strcpy(tr->nick,pq->nick); tr->caps_nick = mymalloc(strlen(pq->nick)+1); strcpy(tr->caps_nick,pq->nick); caps(tr->caps_nick); tr->hostname = mymalloc(strlen(pq->hostname)+1); strcpy(tr->hostname,pq->hostname); tr->xpack = pq->xpack; if (!gdata.quietmode) { char *sizestrstr; sizestrstr = sizestr(0, tr->xpack->st_size); notice_fast(pq->nick, "** Sending You Your Queued Pack Which Is %sB. (Resume Supported)", sizestrstr); mydelete(sizestrstr); } t_setuplisten(tr); sendnamestr = getsendname(tr->xpack->file); privmsg_fast(pq->nick,"\1DCC SEND %s %lu %i %" LLPRINTFMT "u\1", sendnamestr, gdata.ourip, tr->listenport, (unsigned long long)tr->xpack->st_size); mydelete(sendnamestr); mydelete(pq->nick); mydelete(pq->hostname); irlist_delete(&gdata.mainqueue, pq); return; } } /* End of File */