/* check if this host is allowed to send */ static int verify_uploadhost(const char *hostmask) { tupload_t *tu; qupload_t *qu; updatecontext(); if ( verifyupload_group(hostmask) != NULL ) return 0; if ( verifyshell(&gdata.uploadhost, hostmask) != 0 ) return 0; for (tu = irlist_get_head(&gdata.tuploadhost); tu; tu = irlist_get_next(tu)) { if (tu->u_time <= gdata.curtime) continue; if (fnmatch(tu->u_host, hostmask, FNM_CASEFOLD) == 0) return 0; } for (qu = irlist_get_head(&gdata.quploadhost); qu; qu = irlist_get_next(qu)) { if (gnetwork->net != qu->q_net) continue; if (fnmatch(qu->q_host, hostmask, FNM_CASEFOLD) == 0) return 0; } return 1; }
/* show running transfers */ void dinoex_dcl(const userinput *const u) { fetch_curl_t *ft; fetch_queue_t *fq; double dl_total; double dl_size; int progress; updatecontext(); for (ft = irlist_get_head(&fetch_trans); ft; ft = irlist_get_next(ft)) { dl_size = 0.0; curl_easy_getinfo(ft->curlhandle, CURLINFO_SIZE_DOWNLOAD, &dl_size); dl_total = 0.0; curl_easy_getinfo(ft->curlhandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dl_total); progress = 0; progress = ((dl_size + 50) * 100) / max2(dl_total, 1); a_respond(u, " %2i fetch %-32s Receiving %d%%", ft->id, ft->name, progress); } updatecontext(); progress = 0; for (fq = irlist_get_head(&gdata.fetch_queue); fq; fq = irlist_get_next(fq)) { a_respond(u, " %2i fetch %-32s Waiting", ++progress, fq->name); } }
/* sort a linked list with selection sort */ void irlist_sort2(irlist_t *list, int (*cmpfunc)(const void *a, const void *b)) { irlist_t newlist = {0, 0, 0}; void *cur; void *ltry; void *last; while ((cur = irlist_get_head(list))) { irlist_remove(list, cur); ltry = irlist_get_head(&newlist); if (!ltry) { irlist_insert_head(&newlist, cur); continue; } last = NULL; while (ltry) { if (cmpfunc(cur, ltry) < 0) { break; } last = ltry; ltry = irlist_get_next(ltry); } if (!last) { irlist_insert_head(&newlist, cur); } else { irlist_insert_after(&newlist, cur, last); } } *list = newlist; return; }
/* show running transfers in detail */ void dinoex_dcld(const userinput *const u) { fetch_curl_t *ft; fetch_queue_t *fq; char *effective_url; double dl_total; double dl_size; double dl_speed; double dl_time; int progress; int started; int left; updatecontext(); for (ft = irlist_get_head(&fetch_trans); ft; ft = irlist_get_next(ft)) { dl_size = 0.0; curl_easy_getinfo(ft->curlhandle, CURLINFO_SIZE_DOWNLOAD, &dl_size); dl_total = 0.0; curl_easy_getinfo(ft->curlhandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dl_total); dl_speed = 0.0; curl_easy_getinfo(ft->curlhandle, CURLINFO_SPEED_DOWNLOAD, &dl_speed); dl_time = 0.0; curl_easy_getinfo(ft->curlhandle, CURLINFO_TOTAL_TIME, &dl_time); effective_url = NULL; curl_easy_getinfo(ft->curlhandle, CURLINFO_EFFECTIVE_URL, &effective_url); started = min2(359999, gdata.curtime - ft->starttime); left = min2(359999, (dl_total - dl_size) / ((int)(max2(dl_speed, 1)))); progress = ((dl_size + 50) * 100) / max2(dl_total, 1); a_respond(u, " %2i fetch %-32s Receiving %d%%", ft->id, ft->name, progress); a_respond(u, " %s", effective_url ? effective_url : ft->url); a_respond(u, " ^- %5.1fK/s %6" LLPRINTFMT "dK/%6" LLPRINTFMT "dK %2i%c%02i%c/%2i%c%02i%c", (float)(dl_speed/1024), (ir_int64)(dl_size/1024), (ir_int64)(dl_total/1024), started < 3600 ? started/60 : started/60/60 , started < 3600 ? 'm' : 'h', started < 3600 ? started%60 : (started/60)%60 , started < 3600 ? 's' : 'm', left < 3600 ? left/60 : left/60/60 , left < 3600 ? 'm' : 'h', left < 3600 ? left%60 : (left/60)%60 , left < 3600 ? 's' : 'm'); } updatecontext(); progress = 0; for (fq = irlist_get_head(&gdata.fetch_queue); fq; fq = irlist_get_next(fq)) { a_respond(u, " %2i fetch %-32s Waiting", ++progress, fq->name); a_respond(u, " %s", fq->url); } }
/* register active connections for select() */ int chat_select_fdset(int highests) { dccchat_t *chat; for (chat = irlist_get_head(&gdata.dccchats); chat; chat = irlist_get_next(chat)) { if (chat->status == DCCCHAT_CONNECTING) { FD_SET(chat->con.clientsocket, &gdata.writeset); highests = max2(highests, chat->con.clientsocket); continue; } if (chat->status == DCCCHAT_LISTENING) { FD_SET(chat->con.listensocket, &gdata.readset); highests = max2(highests, chat->con.listensocket); continue; } if (chat->status != DCCCHAT_UNUSED) { FD_SET(chat->con.clientsocket, &gdata.readset); highests = max2(highests, chat->con.clientsocket); continue; } } return highests; }
static VALUE cie_mode(VALUE UNUSED(module), VALUE rname, VALUE rmsg) { char *name; char *msg; channel_t *ch; if (NIL_P(rname) || NIL_P(rmsg)) return Qnil; name = rb_obj_as_string_protected(rname); msg = rb_obj_as_string_protected(rmsg); if (!name || !msg) return Qnil; if (gnetwork->serverstatus != SERVERSTATUS_CONNECTED) return Qfalse; if (gnetwork->botstatus != BOTSTATUS_JOINED) return Qfalse; if (name[0] != '#') return Qfalse; for (ch = irlist_get_head(&(gnetwork->channels)); ch; ch = irlist_get_next(ch)) { if (strcasecmp(ch->name, name) == 0) { writeserver(WRITESERVER_NORMAL, "MODE %s %s", name, msg); /* NOTRANSLATE */ return Qtrue; } } return Qfalse; }
/* register active connections for select() */ int l_select_fdset(int highests, int changequartersec) { upload *ul; for (ul = irlist_get_head(&gdata.uploads); ul; ul = irlist_get_next(ul)) { if (ul->ul_status == UPLOAD_STATUS_GETTING) { if (!ul->overlimit) { FD_SET(ul->con.clientsocket, &gdata.readset); highests = max2(highests, ul->con.clientsocket); continue; } if (changequartersec) { FD_SET(ul->con.clientsocket, &gdata.readset); highests = max2(highests, ul->con.clientsocket); } continue; } if (ul->ul_status == UPLOAD_STATUS_CONNECTING) { FD_SET(ul->con.clientsocket, &gdata.writeset); highests = max2(highests, ul->con.clientsocket); continue; } if (ul->ul_status == UPLOAD_STATUS_LISTENING) { FD_SET(ul->con.listensocket, &gdata.readset); highests = max2(highests, ul->con.listensocket); continue; } } return highests; }
static void t_find_debug(const char *nick, const char *filename, const char *remoteport) { transfer *tr; outerror(OUTERROR_TYPE_WARN, "Couldn't find transfer that %s on %s tried to resume!", nick, gnetwork->name); outerror(OUTERROR_TYPE_WARN, "resume trying %s, %s, %d", nick, filename, atoi(remoteport)); if (gdata.debug == 0) return; for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { ioutput(OUT_S, COLOR_NO_COLOR, "transfer %u: %s on %s, %s, %d\n", tr->tr_status, tr->caps_nick, gdata.networks[tr->net].name, tr->xpack->file, tr->con.localport); } }
/* search the DDC transfer a user wants to accept */ unsigned int t_find_transfer(const char *nick, const char *filename, const char *remoteip, const char *remoteport, const char *token) { transfer *tr; unsigned int myid; if (atoi(remoteport) == 0) return 0; myid = atoi(token); for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if (tr->tr_status != TRANSFER_STATUS_RESUME) continue; if (tr->id != myid) continue; if (strcasecmp(tr->caps_nick, nick)) continue; tr->con.remoteaddr = mystrdup(remoteip); t_passive(tr, (unsigned)atoi(remoteport)); return 1; } t_find_debug(nick, filename, remoteport); return 1; }
/* search the DDC transfer a user wants to resume */ unsigned int t_find_resume(const char *nick, const char *filename, const char *localport, const char *bytes, char *token) { char *sendnamestr; transfer *guess; transfer *tr; off_t len; guess = NULL; for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if ((tr->tr_status != TRANSFER_STATUS_LISTENING) && (tr->tr_status != TRANSFER_STATUS_RESUME)) continue; if (strcasecmp(tr->caps_nick, nick)) continue; /* the filename can be converted */ if (guess == NULL) guess = tr; if (strcasestr(tr->xpack->file, filename)) break; if (tr->con.localport == (unsigned)atoi(localport)) break; } if (tr == NULL) { if (guess != NULL) { outerror(OUTERROR_TYPE_WARN, "Guessed transfer that %s on %s tried to resume!", nick, gnetwork->name); outerror(OUTERROR_TYPE_WARN, "resume trying %s, %s, %d", nick, filename, atoi(localport)); tr = guess; } else { t_find_debug(nick, filename, localport); return 1; } } len = atoull(bytes); if (len >= tr->xpack->st_size) { notice(nick, "You can't resume the transfer at a point greater than the size of the file"); ioutput(OUT_S|OUT_L|OUT_D, COLOR_YELLOW, "XDCC [%02i:%s on %s]: Resume attempted beyond end of file ( %" LLPRINTFMT "d >= %" LLPRINTFMT "d )", tr->id, tr->nick, gnetwork->name, len, tr->xpack->st_size); return 1; } t_setresume(tr, bytes); sendnamestr = getsendname(filename); if ((tr->tr_status == TRANSFER_STATUS_RESUME) && (token != NULL)) { privmsg_fast(nick, IRC_CTCP "DCC ACCEPT %s %s %s %s" IRC_CTCP, sendnamestr, localport, bytes, token); /* NOTRANSLATE */ } else { privmsg_fast(nick, IRC_CTCP "DCC ACCEPT %s %s %s" IRC_CTCP, sendnamestr, localport, bytes); /* NOTRANSLATE */ } mydelete(sendnamestr); ioutput(OUT_S|OUT_L|OUT_D, COLOR_YELLOW, "XDCC [%02i:%s on %s]: Resumed at %" LLPRINTFMT "dK", tr->id, tr->nick, gnetwork->name, tr->startresume/1024); return 0; }
/* cancel a running fetch command */ unsigned int fetch_cancel(unsigned int num) { fetch_curl_t *ft; CURLMcode cms; updatecontext(); ft = irlist_get_head(&fetch_trans); while (ft) { if (num > 0) { if (ft->id != num) { ft = irlist_get_next(ft); continue; } } a_respond(&(ft->u), "fetch '%s' canceled", ft->name); cms = curl_multi_remove_handle(cm, ft->curlhandle); if ( cms != 0 ) { outerror(OUTERROR_TYPE_WARN_LOUD, "curl_multi_remove_handle() = %d", cms); } --fetch_started; ft = clean_fetch(ft); start_qupload(); return 0; } return 1; }
/* check if a file is already in transfer */ unsigned int fetch_is_running(const char *file) { fetch_curl_t *ft; updatecontext(); for (ft = irlist_get_head(&fetch_trans); ft; ft = irlist_get_next(ft)) { if (strcmp(ft->name, file) == 0) return 1; } return 0; }
/* match a given file against a list of patterns */ unsigned int verifyshell(irlist_t *list, const char *file) { char *pattern; updatecontext(); pattern = (char *)irlist_get_head(list); while (pattern) { if (fnmatch(pattern, file, FNM_CASEFOLD) == 0) return 1; pattern = (char *)irlist_get_next(pattern); } return 0; }
/* search for a custom uploaddir of a group admin */ static char *verifyupload_group(const char *hostmask) { group_admin_t *ga; updatecontext(); for (ga = irlist_get_head(&gdata.group_admin); ga; ga = irlist_get_next(ga)) { if (fnmatch(ga->g_host, hostmask, FNM_CASEFOLD) == 0) return ga->g_uploaddir; } return NULL; }
/* remove temp uploadhosts */ void clean_uploadhost(void) { tupload_t *tu; updatecontext(); for (tu = irlist_get_head(&gdata.tuploadhost); tu; ) { if (tu->u_time >= gdata.curtime) { tu = irlist_get_next(tu); continue; } mydelete(tu->u_host); tu = irlist_delete(&gdata.tuploadhost, tu); } }
/* register active connections for select() */ int t_select_fdset(int highests, int changequartersec) { transfer *tr; unsigned long sum; unsigned int overlimit; sum = 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]; overlimit = (gdata.maxb && (sum >= gdata.maxb*1024)); for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if (tr->tr_status == TRANSFER_STATUS_LISTENING) { FD_SET(tr->con.listensocket, &gdata.readset); highests = max2(highests, tr->con.listensocket); continue; } if (tr->tr_status == TRANSFER_STATUS_CONNECTING) { FD_SET(tr->con.clientsocket, &gdata.writeset); highests = max2(highests, tr->con.clientsocket); continue; } if (tr->tr_status == TRANSFER_STATUS_SENDING) { if (!overlimit && !tr->overlimit) { FD_SET(tr->con.clientsocket, &gdata.writeset); highests = max2(highests, tr->con.clientsocket); continue; } if (changequartersec || ((tr->bytessent - tr->lastack) > 512*1024)) { FD_SET(tr->con.clientsocket, &gdata.readset); highests = max2(highests, tr->con.clientsocket); } continue; } if (tr->tr_status == TRANSFER_STATUS_WAITING) { FD_SET(tr->con.clientsocket, &gdata.readset); highests = max2(highests, tr->con.clientsocket); continue; } } return highests; }
/* send dcc status line to all chats */ void chat_writestatus(void) { dccchat_t *chat; if (gdata.no_status_chat) return; for (chat = irlist_get_head(&gdata.dccchats); chat; chat = irlist_get_next(chat)) { if (chat->status != DCCCHAT_CONNECTED) continue; gnetwork = &(gdata.networks[chat->net]); writestatus(chat); } gnetwork = NULL; }
static void qupload_started(unsigned int net, const char *nick) { qupload_t *qu; /* start next XDCC GET */ for (qu = irlist_get_head(&gdata.quploadhost); qu; qu = irlist_get_next(qu)) { if (qu->q_state != QUPLOAD_TRYING) continue; if (qu->q_net != net) continue; if (strcasecmp(qu->q_nick, nick) == 0) { qu->q_state = QUPLOAD_RUNNING; return; } } }
/* update or create an entry in the ignore list */ igninfo *get_ignore(const char *hostmask) { igninfo *ignore; for (ignore = irlist_get_head(&gdata.ignorelist); ignore; ignore = irlist_get_next(ignore)) { if (fnmatch(ignore->hostmask, hostmask, FNM_CASEFOLD) != 0) continue; ignore->lastcontact = gdata.curtime; return ignore; } ignore = irlist_add(&gdata.ignorelist, sizeof(igninfo)); ignore->hostmask = mystrdup(hostmask); ignore->lastcontact = gdata.curtime; return ignore; }
static void irc_001(ir_parseline_t *ipl) { char *tptr; ioutput(OUT_S|OUT_L, COLOR_NO_COLOR, "Server welcome: %s", ipl->line); update_server_welcome(ipl->line); /* update server name */ mydelete(gnetwork->curserveractualname); gnetwork->curserveractualname = getpart(ipl->line + 1, 1); /* update nick */ mydelete(gnetwork->user_nick); mydelete(gnetwork->caps_nick); gnetwork->user_nick = mystrdup(ipl->part[2]); gnetwork->caps_nick = mystrdup(ipl->part[2]); caps(gnetwork->caps_nick); gnetwork->nick_number = 0; gnetwork->next_restrict = gdata.curtime + gdata.restrictsend_delay; ++(gdata.needsclear); tptr = get_user_modes(); if (tptr && tptr[0]) { writeserver(WRITESERVER_NOW, "MODE %s %s", gnetwork->user_nick, tptr); } /* server connected raw command */ for (tptr = irlist_get_head(&(gnetwork->server_connected_raw)); tptr; tptr = irlist_get_next(tptr)) { writeserver(WRITESERVER_NORMAL, "%s", tptr); } /* nickserv */ identify_needed(0); }
/* check if a filename is already in a upload */ unsigned int file_uploading(const char *file) { upload *ul; for (ul = irlist_get_head(&gdata.uploads); ul; ul = irlist_get_next(ul)) { if (ul->ul_status == UPLOAD_STATUS_DONE) continue; if (ul->file == NULL) continue; if (strcmp(ul->file, file)) continue; return 1; } #ifdef USE_CURL return fetch_is_running(file); #else return 0; #endif /* USE_CURL */ }
/* start next transfer */ void fetch_next(void) { gnetwork_t *backup; fetch_queue_t *fq; updatecontext(); if (irlist_size(&gdata.fetch_queue) == 0) return; fq = irlist_get_head(&gdata.fetch_queue); if (fq == NULL) return; backup = gnetwork; gnetwork = &(gdata.networks[fq->net]); fetch_now(&(fq->u), fq->uploaddir, fq->name, fq->url); mydelete(fq->u.snick); mydelete(fq->name); mydelete(fq->url); mydelete(fq->uploaddir); irlist_delete(&gdata.fetch_queue, fq); gnetwork = backup; }
/* process all running connections */ void fetch_perform(void) { CURLMcode cms; CURLMsg *msg; CURL *ch; fetch_curl_t *ft; gnetwork_t *backup; char *effective_url; int running; int msgs_in_queue; unsigned int seen = 0; long filetime = 0; do { cms = curl_multi_perform(cm, &running); } while (cms == CURLM_CALL_MULTI_PERFORM); if ( cms != 0 ) { outerror(OUTERROR_TYPE_WARN_LOUD, "curl_multi_perform() = %d", cms); } if (running == fetch_started) return; updatecontext(); backup = gnetwork; do { msg = curl_multi_info_read(cm, &msgs_in_queue); if (msg == NULL) break; ch = msg->easy_handle; ft = irlist_get_head(&fetch_trans); while(ft) { if (ft->curlhandle == ch) { gnetwork = &(gdata.networks[ft->net]); if (ft->errorbuf[0] != 0) outerror(OUTERROR_TYPE_WARN_LOUD, "fetch '%s' failed with %d: %s", ft->name, msg->data.result, ft->errorbuf); if (msg->data.result != 0 ) { a_respond(&(ft->u), "fetch '%s' failed with %d: %s", ft->name, msg->data.result, ft->errorbuf); } else { a_respond(&(ft->u), "fetch '%s' completed", ft->name); ioutput(OUT_L, COLOR_NO_COLOR, "fetch '%s' completed", ft->name); curl_easy_getinfo(ft->curlhandle, CURLINFO_EFFECTIVE_URL, &effective_url); a_respond(&(ft->u), "fetched effective url: '%s'", effective_url); ioutput(OUT_L, COLOR_NO_COLOR, "fetched effective url: '%s'", effective_url); curl_easy_getinfo(ft->curlhandle, CURLINFO_FILETIME, &filetime); a_respond(&(ft->u), "fetched remote time: %ld", filetime); ioutput(OUT_L, COLOR_NO_COLOR, "fetched remote time: %ld", filetime); if (ft->contentname != NULL) { a_respond(&(ft->u), "fetched content name: '%s'", ft->contentname); ioutput(OUT_L, COLOR_NO_COLOR, "fetched content name: '%s'", ft->contentname); } fclose(ft->writefd); /* sync all data to disk */ ft->writefd = NULL; fetch_set_time(ft->fullname, filetime); fetch_rename(ft, effective_url); #ifdef USE_RUBY do_myruby_upload_done( ft->fullname ); #endif /* USE_RUBY */ } updatecontext(); ++seen; --fetch_started; ft = clean_fetch(ft); continue; } ft = irlist_get_next(ft); } } while (msgs_in_queue > 0); updatecontext(); if (seen == 0) outerror(OUTERROR_TYPE_WARN_LOUD, "curlhandle not found %d/%d", running, fetch_started); fetch_started = running; gnetwork = backup; start_qupload(); }
/* handle chat io events */ void chat_perform(void) { dccchat_t *chat; char tempbuffa[INPUT_BUFFER_LENGTH]; ssize_t length; int callval_i; int connect_error; int errno2; SIGNEDSOCK int connect_error_len; unsigned int i; size_t j; updatecontext(); /*----- see if dccchat is sending anything to us ----- */ for (chat = irlist_get_head(&gdata.dccchats); chat; chat = irlist_get_next(chat)) { gnetwork = &(gdata.networks[chat->net]); if (chat->status == DCCCHAT_CONNECTING) { if (FD_ISSET(chat->con.clientsocket, &gdata.writeset)) { connect_error_len = sizeof(connect_error); callval_i = getsockopt(chat->con.clientsocket, SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len); if (callval_i < 0) { errno2 = errno; outerror(OUTERROR_TYPE_WARN, "Couldn't determine dcc connection status on %s: %s", chat->name, strerror(errno)); notice(chat->nick, "DCC Chat Connect Attempt Failed: %s", strerror(errno2)); shutdowndccchat(chat, 0); continue; } if (connect_error) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "DCC Chat Connect Attempt Failed on %s: %s", chat->name, strerror(connect_error)); notice(chat->nick, "DCC Chat Connect Attempt Failed: %s", strerror(connect_error)); shutdowndccchat(chat, 0); continue; } setupdccchatconnected(chat); } continue; } if (chat->status == DCCCHAT_LISTENING) { if (FD_ISSET(chat->con.listensocket, &gdata.readset)) { setupdccchataccept(chat); } continue; } if ((chat->status == DCCCHAT_AUTHENTICATING) || (chat->status == DCCCHAT_CONNECTED)) { if (FD_ISSET(chat->con.clientsocket, &gdata.readset)) { memset(tempbuffa, 0, INPUT_BUFFER_LENGTH); length = recv(chat->con.clientsocket, &tempbuffa, INPUT_BUFFER_LENGTH, MSG_DONTWAIT); if (length < 1) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "DCC Chat Lost on %s: %s", chat->name, (length<0) ? strerror(errno) : "Closed"); notice(chat->nick, "DCC Chat Lost: %s", (length<0) ? strerror(errno) : "Closed"); shutdowndccchat(chat, 0); /* deleted later */ continue; } j = strlen(chat->dcc_input_line); for (i=0; i<(unsigned int)length; i++) { if ((tempbuffa[i] == '\n') || (j == (INPUT_BUFFER_LENGTH-1))) { if (j && (chat->dcc_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'; } continue; } } gnetwork = NULL; }
/* handle transfer ip events */ void t_perform(int changesec, int changequartersec) { transfer *tr; unsigned int i, j; updatecontext(); if (changequartersec) { for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if (tr->nomax) continue; if (tr->maxspeed <= 0) continue; tr->tx_bucket += tr->maxspeed * (1024 / 4); tr->tx_bucket = min2(tr->tx_bucket, MAX_TRANSFER_TX_BURST_SIZE * tr->maxspeed * 1024); } } i = j = select_starting_transfer(); /* first: do from cur to end */ for (tr = irlist_get_nth(&gdata.trans, i); tr; tr = irlist_get_next(tr)) { if (tr->tr_status != TRANSFER_STATUS_SENDING) continue; /*----- look for transfer some ----- send at least once a second, or more if necessary */ if (changequartersec || FD_ISSET(tr->con.clientsocket, &gdata.writeset)) { gnetwork = &(gdata.networks[tr->net]); t_transfersome(tr); } } /* second: do from begin to cur-1 */ for (tr = irlist_get_head(&gdata.trans); tr && j; tr = irlist_get_next(tr), --j) { if (tr->tr_status != TRANSFER_STATUS_SENDING) continue; /*----- look for transfer some ----- send at least once a second, or more if necessary */ if (changequartersec || FD_ISSET(tr->con.clientsocket, &gdata.writeset)) { gnetwork = &(gdata.networks[tr->net]); t_transfersome(tr); } } tr = irlist_get_head(&gdata.trans); while(tr) { gnetwork = &(gdata.networks[tr->net]); /*----- look for listen->connected ----- */ if (tr->tr_status == TRANSFER_STATUS_LISTENING) { if (FD_ISSET(tr->con.listensocket, &gdata.readset)) { t_check_new_connection(tr); tr = irlist_get_next(tr); continue; } /*----- look for listen reminders ----- */ if (changesec) { if (tr->reminded == 0) { if ((gdata.curtime - tr->con.lastcontact) >= 30) t_remind(tr); } if (tr->reminded == 1) { if ((gdata.curtime - tr->con.lastcontact) >= 90) t_remind(tr); } if (tr->reminded == 2) { if ((gdata.curtime - tr->con.lastcontact) >= 150) t_remind(tr); } } } if (tr->tr_status == TRANSFER_STATUS_CONNECTING) { if (FD_ISSET(tr->con.clientsocket, &gdata.writeset)) t_connected(tr); } /*----- look for junk to read ----- */ if ((tr->tr_status == TRANSFER_STATUS_SENDING) || (tr->tr_status == TRANSFER_STATUS_WAITING)) { if (FD_ISSET(tr->con.clientsocket, &gdata.readset)) t_readjunk(tr); } /*----- look for done flushed status ----- */ if (tr->tr_status == TRANSFER_STATUS_WAITING) { t_flushed(tr); } if (changesec) { /*----- look for lost transfers ----- */ if (tr->tr_status != TRANSFER_STATUS_DONE) { t_istimeout(tr); } /*----- look for finished transfers ----- */ if (tr->tr_status == TRANSFER_STATUS_DONE) { char *trnick; trnick = tr->nick; mydelete(tr->caps_nick); mydelete(tr->hostname); mydelete(tr->con.localaddr); mydelete(tr->con.remoteaddr); mydelete(tr->country); tr = irlist_delete(&gdata.trans, tr); if (!gdata.exiting && irlist_size(&gdata.mainqueue) && (irlist_size(&gdata.trans) < gdata.slotsmax)) { check_idle_queue(0); send_from_queue(0, 0, trnick); } mydelete(trnick); continue; } } tr = irlist_get_next(tr); } gnetwork = NULL; }
/* check if a transfer will use more connections per user than allowed */ static void t_check_duplicateip(transfer *const newtr) { igninfo *ignore; char *bhostmask; transfer *tr; unsigned int found; unsigned int num; if (gdata.ignore_duplicate_ip == 0) return; if (gdata.maxtransfersperperson == 0) return; updatecontext(); if (newtr->con.family != AF_INET) return; found = 0; for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if (tr->tr_status != TRANSFER_STATUS_SENDING) continue; if (tr->remoteip != newtr->remoteip) continue; if (!strcmp(tr->hostname, "man")) /* NOTRANSLATE */ continue; ++found; } if (found <= gdata.maxtransfersperperson) return; num = gdata.ignore_duplicate_ip * 60; /* n hours */ for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if (tr->tr_status != TRANSFER_STATUS_SENDING) continue; if (tr->remoteip != newtr->remoteip) continue; if (!strcmp(tr->hostname, "man")) /* NOTRANSLATE */ continue; t_closeconn(tr, "You are being punished for parallel downloads", 0); queue_punish_abuse( "You are being punished for parallel downloads", tr->net, tr->nick); bhostmask = to_hostmask( "*", tr->hostname); /* NOTRANSLATE */ ignore = get_ignore(bhostmask); ignore->flags |= IGN_IGNORING; ignore->flags |= IGN_MANUAL; ignore->bucket = (num*60)/gdata.autoignore_threshold; ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "same IP detected, Ignore activated for %s which will last %u min", bhostmask, num); mydelete(bhostmask); } write_statefile(); }
void t_transfersome (transfer * const t) { unsigned int j; int ii; ssize_t howmuch, howmuch2; size_t attempt; unsigned char *dataptr; off_t offset; #if defined(HAVE_FREEBSD_SENDFILE) struct sf_hdtr sendfile_header = {0, 0, 0, 0}; int jj; #endif updatecontext(); /* max bandwidth start.... */ if (!t->nomax && (t->maxspeed > 0)) { if (t->tx_bucket < TXSIZE) { t->overlimit = 1; return; /* over transfer limit */ } } else { t->tx_bucket = TXSIZE * MAXTXPERLOOP; } 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 && (j >= gdata.maxb*1024)) { if (t->unlimited == 0) return; /* over overall limit */ } t->overlimit = 0; /* max bandwidth end.... */ do { attempt = min2(t->tx_bucket - (t->tx_bucket % TXSIZE), BUFFERSIZE); switch (gdata.transfermethod) { #if defined(HAVE_LINUX_SENDFILE) case TRANSFERMETHOD_LINUX_SENDFILE: offset = t->bytessent; howmuch = sendfile(t->con.clientsocket, t->xpack->file_fd, &offset, attempt); if (howmuch < 0 && ((errno == ENOSYS) || (errno == EOVERFLOW))) { /* sendfile doesn't work on this system, fall back */ outerror(OUTERROR_TYPE_WARN, "%s transfer method does not work on this system, falling back to next available method", "linux-sendfile"); gdata.transfermethod++; return; } else if (howmuch < 0 && errno != EAGAIN) { t_closeconn(t,"Unable to transfer data",errno); return; } else if (howmuch <= 0) { goto done; } howmuch2 = max2(0,howmuch); break; #endif #if defined(HAVE_FREEBSD_SENDFILE) case TRANSFERMETHOD_FREEBSD_SENDFILE: offset = t->bytessent; jj = sendfile(t->xpack->file_fd, t->con.clientsocket, offset, attempt, &sendfile_header, &offset, 0); if (jj < 0 && ((errno == ENOSYS) || (errno == EOPNOTSUPP))) { /* sendfile doesn't work on this system, fall back */ outerror(OUTERROR_TYPE_WARN, "%s transfer method does not work on this system, falling back to next available method", "freebsd-sendfile"); gdata.transfermethod++; return; } else if ((jj < 0) && (errno != EAGAIN)) { t_closeconn(t,"Unable to transfer data",errno); return; } /* * NOTE: according to freebsd man page, * sendfile can set EAGAIN and _STILL_ send data!! */ howmuch = (ssize_t)offset; if (howmuch == 0) { goto done; } howmuch2 = max2(0,howmuch); break; #endif case TRANSFERMETHOD_READ_WRITE: dataptr = gdata.sendbuff; if (t->xpack->file_fd_location != t->bytessent) { offset = lseek(t->xpack->file_fd, t->bytessent, SEEK_SET); if (offset != t->bytessent) { int errno2 = errno; outerror(OUTERROR_TYPE_WARN,"Can't seek location in file '%s': %s", t->xpack->file, strerror(errno)); t_closeconn(t, "Unable to locate data in file", errno2); return; } t->xpack->file_fd_location = t->bytessent; } howmuch = read(t->xpack->file_fd, dataptr, attempt); if (howmuch < 0 && errno != EAGAIN) { int errno2 = errno; outerror(OUTERROR_TYPE_WARN,"Can't read data from file '%s': %s", t->xpack->file, strerror(errno)); t_closeconn(t, "Unable to read data from file", errno2); return; } else if (howmuch <= 0) { goto done; } t->xpack->file_fd_location += howmuch; howmuch2 = send(t->con.clientsocket, dataptr, howmuch, MSG_NOSIGNAL); if (howmuch2 < 0 && errno != EAGAIN) { t_closeconn(t,"Connection Lost",errno); return; } howmuch2 = max2(0,howmuch2); break; #if defined(HAVE_MMAP) case TRANSFERMETHOD_MMAP: if (t->bytessent == t->xpack->st_size) { /* EOF */ goto done; } if (!t->mmap_info || ((ir_uint64)(t->bytessent) >= (t->mmap_info->mmap_offset + (ir_uint64)(t->mmap_info->mmap_size)))) { int callval_i; mmap_info_t *mm; if (t->mmap_info) { t->mmap_info->ref_count--; if (!t->mmap_info->ref_count) { callval_i = munmap(t->mmap_info->mmap_ptr, t->mmap_info->mmap_size); if (callval_i < 0) { outerror(OUTERROR_TYPE_WARN, "Couldn't munmap(): %s", strerror(errno)); } irlist_delete(&t->xpack->mmaps, t->mmap_info); } t->mmap_info = NULL; } /* see if what we want is already mapped */ for (mm = irlist_get_head(&t->xpack->mmaps); mm; mm = irlist_get_next(mm)) { if (mm->mmap_offset == (t->bytessent & ~(IR_MMAP_SIZE-1))) { t->mmap_info = mm; t->mmap_info->ref_count++; break; } } if (!t->mmap_info) { /* nope, add one */ mm = irlist_add(&t->xpack->mmaps, sizeof(mmap_info_t)); t->mmap_info = mm; mm->ref_count++; mm->mmap_offset = t->bytessent & ~(IR_MMAP_SIZE-1); mm->mmap_size = IR_MMAP_SIZE; if ((mm->mmap_offset + (ir_uint64)(mm->mmap_size)) > (ir_uint64)(t->xpack->st_size)) { mm->mmap_size = t->xpack->st_size - mm->mmap_offset; } mm->mmap_ptr = mmap(NULL, mm->mmap_size, PROT_READ, MAP_SHARED, t->xpack->file_fd, mm->mmap_offset); if ((mm->mmap_ptr == (unsigned char *)MAP_FAILED) || (!mm->mmap_ptr)) { irlist_delete(&t->xpack->mmaps, mm); t->mmap_info = NULL; if (errno == ENOMEM) { /* mmap doesn't work on this system, fall back */ outerror(OUTERROR_TYPE_WARN, "%s transfer method does not work on this system, falling back to next available method", "mmap"); gdata.transfermethod++; } else { t_closeconn(t,"Unable to access file",errno); } return; } if (gdata.debug > 53) { ioutput(OUT_S, COLOR_BLUE, "mmap() [%p] offset=0x%.8" LLPRINTFMT "X size=0x%.8" LLPRINTFMT "X", mm->mmap_ptr, (ir_uint64)(mm->mmap_offset), (ir_uint64)(mm->mmap_size)); } } } dataptr = t->mmap_info->mmap_ptr + t->bytessent - t->mmap_info->mmap_offset; if ((t->bytessent + attempt) > (t->mmap_info->mmap_offset + t->mmap_info->mmap_size)) { howmuch = (t->mmap_info->mmap_offset + t->mmap_info->mmap_size) - t->bytessent; } else { howmuch = attempt; } if (howmuch == 0) { /* EOF */ goto done; } howmuch2 = send(t->con.clientsocket, dataptr, howmuch, MSG_NOSIGNAL); if (howmuch2 < 0 && errno != EAGAIN) { t_closeconn(t,"Connection Lost",errno); return; } howmuch2 = max2(0,howmuch2); break; #endif default: t_closeconn(t,"Transfer Method unknown!", 0); return; } if (howmuch2 > 0) { t->con.lastcontact = gdata.curtime; } t->bytessent += howmuch2; gdata.xdccsum[gdata.curtime%XDCC_SENT_SIZE] += howmuch2; if (t->unlimited == 0) gdata.xdccsent[gdata.curtime%XDCC_SENT_SIZE] += howmuch2; t->tx_bucket -= howmuch2; j += howmuch2; gdata.totalsent += howmuch2; for (ii=0; ii<NUMBER_TRANSFERLIMITS; ii++) { gdata.transferlimits[ii].used += (ir_uint64)howmuch2; } if (gdata.debug > 51) { ioutput(OUT_S, COLOR_BLUE, "File %ld Write %ld", (long)howmuch, (long)howmuch2); } /* if over 50% send one to be fair */ if ( gdata.maxb && ((j*100) > (gdata.maxb*1024*50)) ) { goto done; } } while ((t->tx_bucket >= TXSIZE) && (howmuch2 > 0)); done: if (t->bytessent >= t->xpack->st_size) { #ifdef HAVE_MMAP if (t->mmap_info) { t->mmap_info->ref_count--; if (!t->mmap_info->ref_count) { int callval_i; callval_i = munmap(t->mmap_info->mmap_ptr, t->mmap_info->mmap_size); if (callval_i < 0) { outerror(OUTERROR_TYPE_WARN, "Couldn't munmap(): %s", strerror(errno)); } irlist_delete(&t->xpack->mmaps, t->mmap_info); } t->mmap_info = NULL; } #endif t->tr_status = TRANSFER_STATUS_WAITING; } return; }
void parseconsole(void) { static char console_escape_seq[maxtextlengthshort]; unsigned char tempbuffa[INPUT_BUFFER_LENGTH]; int length; unsigned int linelength; userinput ui; unsigned int i, j; updatecontext(); bzero(console_escape_seq, sizeof(console_escape_seq)); if (is_fd_readable(fileno(stdin))) { memset(tempbuffa, 0, INPUT_BUFFER_LENGTH); length = read (fileno(stdin), &tempbuffa, INPUT_BUFFER_LENGTH); if (length < 1) { outerror(OUTERROR_TYPE_CRASH,"read from stdin failed: %s",(length<0) ? strerror(errno) : "EOF!"); } linelength = strlen(gdata.console_input_line); for (i=0; i<(unsigned int)length; i++) { if (console_escape_seq[0] != '\0') { size_t esc_len = strlen(console_escape_seq); if (esc_len < (maxtextlengthshort-2)) { console_escape_seq[esc_len]=tempbuffa[i]; esc_len++; if (((tempbuffa[i] >= 'a') && (tempbuffa[i] <= 'z')) || ((tempbuffa[i] >= 'A') && (tempbuffa[i] <= 'Z'))) { /* process sequence */ if (console_escape_seq[1] == '[') { if (console_escape_seq[esc_len-1] == 'A') { /* up */ int count; if (esc_len > 3) { count=atoi(&console_escape_seq[2]); } else { count=1; } while(count--) { if (gdata.console_history_offset) { gdata.console_history_offset--; strncpy(gdata.console_input_line, irlist_get_nth(&gdata.console_history, gdata.console_history_offset), INPUT_BUFFER_LENGTH-1); linelength = strlen(gdata.console_input_line); gdata.curcol = linelength; } } } else if (console_escape_seq[esc_len-1] == 'B') { /* down */ int count; if (esc_len > 3) { count=atoi(&console_escape_seq[2]); } else { count=1; } while(count--) { gdata.console_history_offset++; if (gdata.console_history_offset < irlist_size(&gdata.console_history)) { strncpy(gdata.console_input_line, irlist_get_nth(&gdata.console_history, gdata.console_history_offset), INPUT_BUFFER_LENGTH-1); linelength = strlen(gdata.console_input_line); gdata.curcol = linelength; } else { memset(gdata.console_input_line, 0, INPUT_BUFFER_LENGTH); linelength = 0; gdata.curcol = 0; } gdata.console_history_offset = min2(gdata.console_history_offset,irlist_size(&gdata.console_history)); } } else if (console_escape_seq[esc_len-1] == 'C') { /* right */ int count; if (esc_len > 3) { count=atoi(&console_escape_seq[2]); } else { count=1; } gdata.curcol += count; if (gdata.curcol > linelength) gdata.curcol = linelength; } else if (console_escape_seq[esc_len-1] == 'D') { /* left */ unsigned int count; if (esc_len > 3) { count=atoi(&console_escape_seq[2]); } else { count=1; } if (count <= gdata.curcol) gdata.curcol -= count; } /* else ignore */ } /* else ignore */ memset(console_escape_seq, 0, maxtextlengthshort); } } else { /* sequence is too long, ignore */ memset(console_escape_seq, 0, maxtextlengthshort); } } else if (tempbuffa[i] == '\x1b') { console_escape_seq[0]=tempbuffa[i]; } else if ((tempbuffa[i] == '\t') && gdata.console_input_line[0]) { if (!gdata.attop) gototop(); j = u_expand_command(); gdata.curcol += j; linelength += j; } else if (tempbuffa[i] == '\n') { char *hist; hist = irlist_get_tail(&gdata.console_history); if ((!hist || strcmp(hist,gdata.console_input_line)) && gdata.console_input_line[0]) { hist = irlist_add(&gdata.console_history, linelength+1); strncpy(hist, gdata.console_input_line, linelength); } if (irlist_size(&gdata.console_history) > MAX_HISTORY_SIZE) { irlist_delete(&gdata.console_history, irlist_get_head(&gdata.console_history)); } gdata.console_history_offset = irlist_size(&gdata.console_history); if (!gdata.attop) gototop(); u_fillwith_console(&ui,gdata.console_input_line); u_parseit(&ui); gdata.curcol=0; memset(gdata.console_input_line, 0, INPUT_BUFFER_LENGTH); } else if (isprintable(tempbuffa[i])) { if (linelength < (INPUT_BUFFER_LENGTH-2)) { for (j=linelength; j>gdata.curcol; j--) { gdata.console_input_line[j] = gdata.console_input_line[j-1]; } gdata.console_input_line[gdata.curcol]=tempbuffa[i]; gdata.curcol++; linelength++; } } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VINTR]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VQUIT]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VERASE]) { if (gdata.curcol) { for (j=gdata.curcol-1; j<linelength; j++) { gdata.console_input_line[j] = gdata.console_input_line[j+1]; } linelength--; gdata.console_input_line[linelength] = '\0'; gdata.curcol--; } } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VWERASE]) { while (gdata.curcol && (gdata.console_input_line[gdata.curcol-1] == ' ')) { for (j=gdata.curcol-1; j<linelength; j++) { gdata.console_input_line[j] = gdata.console_input_line[j+1]; } linelength--; gdata.console_input_line[linelength] = '\0'; gdata.curcol--; } while (gdata.curcol && (gdata.console_input_line[gdata.curcol-1] != ' ')) { for (j=gdata.curcol-1; j<linelength; j++) { gdata.console_input_line[j] = gdata.console_input_line[j+1]; } linelength--; gdata.console_input_line[linelength] = '\0'; gdata.curcol--; } while (gdata.curcol && (gdata.console_input_line[gdata.curcol-1] == ' ')) { for (j=gdata.curcol-1; j<linelength; j++) { gdata.console_input_line[j] = gdata.console_input_line[j+1]; } linelength--; gdata.console_input_line[linelength] = '\0'; gdata.curcol--; } } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VKILL]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VEOF]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VSTART]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VSTOP]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VSUSP]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VLNEXT]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VREPRINT]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VDISCARD]) { } else if (tempbuffa[i] == '\x01') /* Ctrl-A */ { gdata.curcol = 0; } else if (tempbuffa[i] == '\x05') /* Ctrl-E */ { gdata.curcol = linelength; } } drawbot(); } }
void t_checkminspeed(transfer * const t) { char *hostmask; char *tempstr2; updatecontext(); if (t->tr_status != TRANSFER_STATUS_SENDING) return; /* no checking unless we're sending */ if (t->con.connecttime+MIN_TL > gdata.curtime) return; /* no checking until time has passed */ if (t->nomin || (t->xpack->minspeed) == 0.0) return; /* no minspeed for this transfer */ if ( t->lastspeed+0.11 > t->xpack->minspeed ) return; /* over minspeed */ if (gdata.no_minspeed_on_free) { if (irlist_size(&gdata.trans) < gdata.slotsmax) return; /* free slots */ } tempstr2 = mymalloc(maxtextlength); snprintf(tempstr2, maxtextlength, "Under Min Speed Requirement, %2.1fK/sec is less than %2.1fK/sec", t->lastspeed,t->xpack->minspeed); t_closeconn(t,tempstr2,0); mydelete(tempstr2); if (gdata.punishslowusers) { igninfo *ignore; transfer *tr; gnetwork_t *backup; for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if ((tr->tr_status != TRANSFER_STATUS_DONE) && (strcasecmp(tr->nick,t->nick) == 0)) { t_closeconn(tr, "You are being punished for your slowness", 0); } } queue_punish_abuse("You are being punished for your slowness", t->net, t->nick); hostmask = to_hostmask( "*", t->hostname); ignore = get_ignore(hostmask); mydelete(hostmask); ignore->flags |= IGN_IGNORING; ignore->bucket = (gdata.punishslowusers*60)/gdata.autoignore_threshold; backup = gnetwork; gnetwork = &(gdata.networks[t->net]); ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Punish-ignore activated for (%s on %s) (%s) %u minutes", t->nick, gdata.networks[ t->net ].name, ignore->hostmask, gdata.punishslowusers); notice(t->nick, "Punish-ignore activated for %s (%s) %u minutes", t->nick, ignore->hostmask, gdata.punishslowusers); gnetwork = backup; write_statefile(); } }
static void mainloop (void) { /* data is persistant across calls */ static struct timeval timestruct; static int changequartersec, changesec, changemin, changehour; static time_t lasttime, lastmin, lasthour, last4sec, last5sec, last20sec; static time_t lastautoadd; static time_t last3min, last2min, lastignoredec; static int first_loop = 1; static ir_uint64 last250ms; userinput *pubplist; userinput *urehash; ir_uint64 xdccsent; unsigned int i; int highests; unsigned int ss; upload *ul; transfer *tr; channel_t *ch; xdcc *xd; dccchat_t *chat; updatecontext(); gnetwork = NULL; if (first_loop) { /* init if first time called */ FD_ZERO(&gdata.readset); FD_ZERO(&gdata.writeset); changehour=changemin=changesec=changequartersec=0; gettimeofday(×truct, NULL); last250ms = gdata.curtimems; gdata.curtimems = timeval_to_ms(×truct); ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Startup" " running: %ld ms", (long)(gdata.curtimems - last250ms)); gdata.curtime = timestruct.tv_sec; lasttime=gdata.curtime; last250ms = gdata.curtimems; lastmin=(lasttime/60)-1; lasthour=(lasttime/60/60)-1; last4sec = last5sec = last20sec = last2min = last3min = lasttime; lastignoredec = lasttime; for (ss=0; ss<gdata.networks_online; ss++) { gdata.networks[ss].lastnotify = lasttime; gdata.networks[ss].lastslow = lasttime; gdata.networks[ss].server_input_line[0] = '\0'; } gdata.cursendptr = 0; lastautoadd = gdata.curtime + 60; first_loop = 0; } updatecontext(); FD_ZERO(&gdata.readset); FD_ZERO(&gdata.writeset); FD_ZERO(&gdata.execset); highests = 0; #ifdef USE_CURL fetch_multi_fdset(&gdata.readset, &gdata.writeset, &gdata.execset, &highests); #endif /* USE_CURL */ highests = irc_select(highests); if (!gdata.background) { FD_SET(fileno(stdin), &gdata.readset); highests = max2(highests, fileno(stdin)); } highests = chat_select_fdset(highests); highests = t_select_fdset(highests, changequartersec); highests = l_select_fdset(highests, changequartersec); #ifndef WITHOUT_TELNET highests = telnet_select_fdset(highests); #endif /* WITHOUT_TELNET */ #ifndef WITHOUT_HTTP highests = h_select_fdset(highests, changequartersec); #endif /* WITHOUT_HTTP */ 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(); if (gdata.debug > 81) { select_dump("try", highests); } if (gdata.attop) gotobot(); tostdout_write(); gettimeofday(×truct, NULL); gdata.selecttimems = timeval_to_ms(×truct); if (ir_kqueue_select(highests+1, &gdata.readset, &gdata.writeset, &gdata.execset) < 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); FD_ZERO(&gdata.execset); } if (gdata.debug > 81) { select_dump("got", highests); } /*----- one second check ----- */ updatecontext(); if (gettimeofday(×truct, NULL) < 0) { outerror(OUTERROR_TYPE_CRASH,"gettimeofday() failed! %s\n",strerror(errno)); } gdata.curtimems = timeval_to_ms(×truct); gdata.curtime = timestruct.tv_sec; if (gdata.curtimems > gdata.selecttimems + 1000) outerror(OUTERROR_TYPE_WARN, "Iroffer was blocked for %lims", (long)(gdata.curtimems - gdata.selecttimems)); /* 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 - MAX_WAKEUP_WARN) { 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 + MAX_WAKEUP_WARN) { 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) { dump_slow_context(); } } if (gdata.curtime > lasttime + MAX_WAKEUP_ERR) { 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; } if (gdata.needsshutdown) { gdata.needsshutdown = 0; shutdowniroffer(); } if (gdata.needsreap) { gdata.needsreap = 0; irc_resolved(); } #ifdef USE_CURL fetch_perform(); #endif /* USE_CURL */ updatecontext(); if (changesec) { gdata.totaluptime++; gdata.xdccsent[(gdata.curtime+1)%XDCC_SENT_SIZE] = 0; gdata.xdccrecv[(gdata.curtime+1)%XDCC_SENT_SIZE] = 0; xdccsent = 0; for (i=0; i<XDCC_SENT_SIZE; i++) xdccsent += (ir_uint64)gdata.xdccsum[i]; if (((float)xdccsent)/XDCC_SENT_SIZE/1024.0 > gdata.sentrecord) gdata.sentrecord = ((float)xdccsent)/XDCC_SENT_SIZE/1024.0; gdata.xdccsum[(gdata.curtime+1)%XDCC_SENT_SIZE] = 0; run_delayed_jobs(); } updatecontext(); /*----- see if anything waiting on console ----- */ gdata.needsclear = 0; if (!gdata.background && FD_ISSET(fileno(stdin), &gdata.readset)) parseconsole(); irc_perform(changesec); l_perform(changesec); chat_perform(); t_perform(changesec, changequartersec); #ifndef WITHOUT_TELNET telnet_perform(); #endif /* WITHOUT_TELNET */ #ifndef WITHOUT_HTTP h_perform(changesec, changequartersec); #endif /* WITHOUT_HTTP */ /*----- time for a delayed shutdown? ----- */ if (changesec && gdata.delayedshutdown) { if (!irlist_size(&gdata.trans)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Delayed Shutdown Activated, No Transfers Remaining"); shutdowniroffer(); } } updatecontext(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /*----- send server stuff ----- */ if (changesec) { sendserver(); if (gdata.curtime%INAMNT_SIZE == (INAMNT_SIZE-1)) gnetwork->inamnt[0] = 0; else gnetwork->inamnt[gdata.curtime%INAMNT_SIZE+1] = 0; } /*----- see if we can send out some xdcc lists */ if (changesec && gnetwork->serverstatus == SERVERSTATUS_CONNECTED) { if (!irlist_size((&gnetwork->serverq_normal)) && !irlist_size(&(gnetwork->serverq_slow))) sendxdlqueue(); } } gnetwork = NULL; /*----- 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 ((unsigned int)localt->tm_hour >= gdata.overallmaxspeeddaytimestart && (unsigned int)localt->tm_hour < gdata.overallmaxspeeddaytimeend && ( gdata.overallmaxspeeddaydays & (1 << (unsigned int)localt->tm_wday)) ) gdata.maxb = gdata.overallmaxspeeddayspeed; } isrotatelog(); expire_options(); } /*----- see if we've hit a transferlimit or need to reset counters */ if (changesec) { unsigned int ii; unsigned int transferlimits_over = 0; for (ii=0; ii<NUMBER_TRANSFERLIMITS; ii++) { /* reset counters? */ if ((!gdata.transferlimits[ii].ends) || (gdata.transferlimits[ii].ends < gdata.curtime)) { struct tm *localt; if (gdata.transferlimits[ii].limit && gdata.transferlimits[ii].ends) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Resetting %s transfer limit, used %" LLPRINTFMT "uMB of the %" LLPRINTFMT "uMB limit", transferlimit_type_to_string(ii), gdata.transferlimits[ii].used / 1024 / 1024, gdata.transferlimits[ii].limit / 1024 / 1024); } /* find our next end time */ localt = localtime(&gdata.curtime); localt->tm_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 = gdata.start_of_month; localt->tm_mon++; break; default: outerror(OUTERROR_TYPE_CRASH, "unknown type %u", ii); } /* tm_wday and tm_yday are ignored in mktime() */ gdata.transferlimits[ii].ends = mktime(localt); gdata.transferlimits[ii].used = 0; if ( ii == TRANSFERLIMIT_DAILY ) reset_download_limits(); } if (!transferlimits_over && gdata.transferlimits[ii].limit && (gdata.transferlimits[ii].used >= gdata.transferlimits[ii].limit)) { transferlimits_over = 1 + ii; if (!gdata.transferlimits_over) { char *tempstr = transfer_limit_exceeded_msg(ii); ioutput(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)); /* remove queued users */ queue_all_remove(&gdata.mainqueue, tempstr); queue_all_remove(&gdata.idlequeue, tempstr); /* stop transfers */ for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if (tr->tr_status != TRANSFER_STATUS_DONE) { gnetwork = &(gdata.networks[tr->net]); t_closeconn(tr,tempstr,0); } } gnetwork = NULL; mydelete(tempstr); } } } if (gdata.transferlimits_over != transferlimits_over) { if (!transferlimits_over) { ioutput(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 && ((unsigned)gdata.curtime > (lastignoredec + gdata.autoignore_threshold))) { igninfo *ignore; lastignoredec += gdata.autoignore_threshold; ignore = irlist_get_head(&gdata.ignorelist); while(ignore) { ignore->bucket--; if ((ignore->flags & IGN_IGNORING) && (ignore->bucket == 0)) { ignore->flags &= ~IGN_IGNORING; ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Ignore removed for %s",ignore->hostmask); write_statefile(); } if (ignore->bucket == 0) { mydelete(ignore->hostmask); ignore = irlist_delete(&gdata.ignorelist, ignore); } else { ignore = irlist_get_next(ignore); } } } /*----- periodicmsg_time seconds ----- */ if (changesec) { send_periodicmsg(); } updatecontext(); /*----- 5 seconds ----- */ if (changesec && (gdata.curtime - last5sec > 4)) { last5sec = gdata.curtime; updatecontext(); /*----- server timeout ----- */ for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); if (gdata.needsshutdown) continue; if ((gnetwork->serverstatus == SERVERSTATUS_CONNECTED) && (gdata.curtime > gnetwork->lastservercontact + SRVRTOUT)) { if (gnetwork->servertime < 3) { const char *servname = gnetwork->curserveractualname ? gnetwork->curserveractualname : gnetwork->curserver.hostname; size_t len = 6 + strlen(servname); char *tempstr3 = mymalloc(len + 1); snprintf(tempstr3, len + 1, "PING %s\n", servname); writeserver_ssl(tempstr3, len); if (gdata.debug > 0) { tempstr3[len-1] = '\0'; len--; ioutput(OUT_S, COLOR_MAGENTA, "<NORES<: %s", tempstr3); } mydelete(tempstr3); gnetwork->servertime++; } else if (gnetwork->servertime == 3) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_RED, "Closing Server Connection on %s: No Response for %u minutes.", gnetwork->name, SRVRTOUT/60); close_server(); gnetwork->servertime = 0; } } /*----- ping server ----- */ if (gnetwork->recentsent) { pingserver(); gnetwork->recentsent--; } } } /* networks */ gnetwork = NULL; /*----- 4 seconds ----- */ if (changesec && (gdata.curtime - last4sec > 3)) { /*----- update lastspeed, check minspeed ----- */ tr = irlist_get_head(&gdata.trans); while(tr) { if ( tr->con.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->con.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(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /*----- plist stuff ----- */ if ((gnetwork->serverstatus == SERVERSTATUS_CONNECTED) && changemin && irlist_size(&gdata.xdccs) && !gdata.transferlimits_over && (irlist_size(&(gnetwork->serverq_channel)) < irlist_size(&gdata.xdccs)) && (!gdata.queuesize || irlist_size(&gdata.mainqueue) < gdata.queuesize) && (gdata.nolisting <= gdata.curtime)) { char *tchanf = NULL, *tchanm = NULL, *tchans = NULL; for(ch = irlist_get_head(&(gnetwork->channels)); ch; ch = irlist_get_next(ch)) { if ((ch->flags & CHAN_ONCHAN) && (ch->nextann < gdata.curtime) && ch->plisttime && (((gdata.curtime / 60) % ch->plisttime) == ch->plistoffset)) { ch->nextmsg = gdata.curtime + ch->delay; if (ch->pgroup != NULL) { ioutput(OUT_S|OUT_D, COLOR_NO_COLOR, "Plist sent to %s (pgroup)", ch->name); pubplist = mycalloc(sizeof(userinput)); pubplist->method = method_xdl_channel; pubplist->net = gnetwork->net; pubplist->level = ADMIN_LEVEL_PUBLIC; a_fillwith_plist(pubplist, ch->name, ch); u_parseit(pubplist); mydelete(pubplist); continue; } if (ch->flags & CHAN_MINIMAL) { if (tchanm) { strncat(tchanm,",",maxtextlength-strlen(tchanm)-1); strncat(tchanm,ch->name,maxtextlength-strlen(tchanm)-1); } else { tchanm = mymalloc(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 = mymalloc(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 = mymalloc(maxtextlength); strncpy(tchanf,ch->name,maxtextlength-1); } } } } if (tchans) { if (gdata.restrictprivlist && !gdata.creditline && !irlist_size(&gdata.headline)) { ioutput(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(OUT_S|OUT_D, COLOR_NO_COLOR, "Plist sent to %s (summary)", tchans); pubplist = mycalloc(sizeof(userinput)); a_fillwith_msg2(pubplist, tchans, "XDL"); pubplist->method = method_xdl_channel_sum; u_parseit(pubplist); mydelete(pubplist); } mydelete(tchans); } if (tchanf) { ioutput(OUT_S|OUT_D, COLOR_NO_COLOR, "Plist sent to %s (full)", tchanf); pubplist = mycalloc(sizeof(userinput)); a_fillwith_plist(pubplist, tchanf, NULL); pubplist->method = method_xdl_channel; u_parseit(pubplist); mydelete(pubplist); mydelete(tchanf); } if (tchanm) { ioutput(OUT_S|OUT_D, COLOR_NO_COLOR, "Plist sent to %s (minimal)", tchanm); pubplist = mycalloc(sizeof(userinput)); a_fillwith_msg2(pubplist, tchanm, "XDL"); pubplist->method = method_xdl_channel_min; u_parseit(pubplist); mydelete(pubplist); mydelete(tchanm); } } } /* networks */ gnetwork = NULL; updatecontext(); /*----- low bandwidth send, save state file ----- */ if (changesec && (gdata.curtime - last3min > 180)) { last3min = gdata.curtime; xdccsent = 0; for (i=0; i<XDCC_SENT_SIZE; i++) xdccsent += (ir_uint64)gdata.xdccsent[i]; xdccsent /= XDCC_SENT_SIZE*1024; if ((xdccsent < (unsigned)gdata.lowbdwth) && !gdata.exiting && irlist_size(&gdata.mainqueue) && (irlist_size(&gdata.trans) < gdata.maxtrans)) { check_idle_queue(0); send_from_queue(1, 0, NULL); } write_files(); } updatecontext(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /*----- queue notify ----- */ if (changesec && gdata.notifytime && (!gdata.quietmode) && ((unsigned)gdata.curtime > (gnetwork->lastnotify + (gdata.notifytime*60)))) { gnetwork->lastnotify = gdata.curtime; if (gnetwork->serverstatus == SERVERSTATUS_CONNECTED) { if ((irlist_size(&(gnetwork->serverq_fast)) >= 10) || (irlist_size(&(gnetwork->serverq_normal)) >= 10) || (irlist_size(&(gnetwork->serverq_slow)) >= 50)) { ioutput(OUT_S|OUT_D|OUT_L, COLOR_NO_COLOR, "notifications skipped on %s, server queue is rather large", gnetwork->name); } else { notifyqueued(); notifybandwidth(); notifybandwidthtrans(); } } } } /* networks */ gnetwork = NULL; updatecontext(); /*----- log stats / remote admin stats ----- */ if ( changesec && ((unsigned)gdata.curtime >= (last2min + gdata.status_time_dcc_chat))) { last2min = gdata.curtime; if (gdata.logstats) { logstat(); chat_writestatus(); } } updatecontext(); /* look to see if any files changed */ if (changesec) look_for_file_remove(); updatecontext(); /*----- 20 seconds ----- */ if (changesec && (gdata.curtime - last20sec > 19)) { expire_badip(); if (gdata.logfd != FD_UNUSED) { /* cycle */ close(gdata.logfd); gdata.logfd = FD_UNUSED; } updatecontext(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /* try rejoining channels not on */ ch = irlist_get_head(&(gnetwork->channels)); while(ch) { if ((gnetwork->serverstatus == SERVERSTATUS_CONNECTED) && !(ch->flags & CHAN_ONCHAN)) { joinchannel(ch); } ch = irlist_get_next(ch); } } /* networks */ gnetwork = NULL; last20sec = gdata.curtime; updatecontext(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /* try to regain nick */ if (!gnetwork->user_nick || strcmp(get_config_nick(), gnetwork->user_nick)) { writeserver(WRITESERVER_NORMAL, "NICK %s", get_config_nick()); } } /* networks */ gnetwork = NULL; updatecontext(); /* update status line */ if (!gdata.background && !gdata.noscreen) { char tempstr[maxtextlength]; char tempstr2[maxtextlengthshort]; if (gdata.attop) gotobot(); tostdout(IRVT_SAVE_CURSOR); getstatusline(tempstr,maxtextlength); tempstr[min2(maxtextlength-2,gdata.termcols-4)] = '\0'; snprintf(tempstr2, maxtextlengthshort, IRVT_CURSOR_HOME1 "[ %%-%us ]", gdata.termlines - 1, gdata.termcols - 4); tostdout(tempstr2,tempstr); tostdout(IRVT_CURSOR_HOME2 IRVT_UNSAVE_CURSOR, gdata.termlines, gdata.termcols); } admin_jobs(); #ifdef USE_RUBY rehash_myruby(1); #endif /* USE_RUBY */ delayed_announce(); } updatecontext(); if (changemin) { reverify_restrictsend(); update_hour_dinoex(lastmin); check_idle_queue(0); clean_uploadhost(); auto_rehash(); } updatecontext(); if ((gdata.md5build.file_fd != FD_UNUSED) && FD_ISSET(gdata.md5build.file_fd, &gdata.readset)) { ssize_t howmuch; #if defined(_OS_CYGWIN) int reads_per_loop = 32; #else /* _OS_CYGWIN */ int reads_per_loop = 64; #endif /* _OS_CYGWIN */ assert(gdata.md5build.xpack); while (reads_per_loop--) { howmuch = read(gdata.md5build.file_fd, gdata.sendbuff, BUFFERSIZE); if (gdata.debug >30) { ioutput(OUT_S, COLOR_YELLOW, "MD5: [Pack %u] read %ld", number_of_pack(gdata.md5build.xpack), (long)howmuch); } if ((howmuch < 0) && (errno != EAGAIN)) { outerror(OUTERROR_TYPE_WARN, "MD5: [Pack %u] Can't read data from file '%s': %s", number_of_pack(gdata.md5build.xpack), gdata.md5build.xpack->file, strerror(errno)); event_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 */ outerror(OUTERROR_TYPE_WARN, "MD5: [Pack %u] Can't read data from file '%s': %s", number_of_pack(gdata.md5build.xpack), gdata.md5build.xpack->file, "truncated"); start_md5_hash(gdata.md5build.xpack, number_of_pack(gdata.md5build.xpack)); break; } /* else got data */ MD5Update(&gdata.md5build.md5sum, gdata.sendbuff, howmuch); if (!gdata.nocrc32) crc32_update((char *)gdata.sendbuff, howmuch); gdata.md5build.bytes += howmuch; if (gdata.md5build.bytes == gdata.md5build.xpack->st_size) { complete_md5_hash(); break; } } } if (!gdata.nomd5sum && changesec && (!gdata.md5build.xpack)) { unsigned int packnum = 1; /* see if any pack needs a md5sum calculated */ if (gdata.nomd5_start <= gdata.curtime) for (xd = irlist_get_head(&gdata.xdccs); xd; xd = irlist_get_next(xd), packnum++) { if (!gdata.nocrc32) { if (!xd->has_crc32) xd->has_md5sum = 0; /* force recheck with crc */ } if (!xd->has_md5sum) { if (verifyshell(&gdata.md5sum_exclude, xd->file)) continue; if (!gdata.attop) gototop(); start_md5_hash(xd, packnum); break; } } } updatecontext(); if (gdata.exiting && has_closed_servers()) { 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("iroffer exited\n\n"); exit_iroffer(0); } updatecontext(); if (gdata.needsrehash) { gdata.needsrehash = 0; urehash = mycalloc(sizeof(userinput)); a_fillwith_msg2(urehash, NULL, "REHASH"); urehash->method = method_out_all; /* just OUT_S|OUT_L|OUT_D it */ urehash->net = 0; urehash->level = ADMIN_LEVEL_FULL; 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); } } if (gdata.autoadd_time > 0) { if (changesec && ((unsigned)gdata.curtime > (lastautoadd + gdata.autoadd_time))) { lastautoadd = gdata.curtime; autoadd_all(); } } /* END */ updatecontext(); if (gdata.needsclear) drawbot(); changehour=changemin=0; }