/* 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);
  }
}
Example #2
0
/* 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 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);
  }
}
Example #4
0
/* 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;
}
Example #5
0
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;
}
/* 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;
}
Example #7
0
/* 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 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;
}
/* 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;
}
/* 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;
}
Example #14
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;
}
Example #15
0
/* 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;
}
Example #17
0
/* 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;
}
Example #18
0
/* 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;
}
Example #19
0
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;
    }
  }
}
Example #20
0
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);
}
Example #21
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 */
}
Example #22
0
/* 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;
}
/* sort a linked list with merge sort */
void irlist_sort2(irlist_t *list, int (*cmpfunc)(const void *a, const void *b))
{
  irlist_t newlist = {0, 0, 0};
  irlist_t *p;
  irlist_t *q;
  irlist_t *e;
  irlist_t *tail;
  int insize;
  int nmerges;
  int psize;
  int qsize;
  int i;

  insize = 1;
  for(;;) {
    p = irlist_get_head(list);
    list = NULL;
    tail = NULL;
    nmerges = 0; /* count number of merges we do in this pass */

    while (p) {
      ++nmerges;  /* there exists a merge to be done */
      /* step `insize' places along from p */
      q = p;
      psize = 0;
      for (i = 0; i < insize; ++i) {
        ++psize;
        q = irlist_get_next(q);
        if (!q) break;
      }

      /* if q hasn't fallen off end, we have two lists to merge */
      qsize = insize;

      /* now we have two lists; merge them */
      while (psize > 0 || (qsize > 0 && q)) {

        /* decide whether next element of merge comes from p or q */
        if (psize == 0) {
          /* p is empty; e must come from q. */
          e = q;
          q = irlist_get_next(q);
	  irlist_remove(list, e);
          qsize--;
        } else if (qsize == 0 || !q) {
          /* q is empty; e must come from p. */
          e = p;
          p = irlist_get_next(p);
	  irlist_remove(list, e);
          psize--;
        } else if (cmpfunc(p, q) <= 0) {
          /* First element of p is lower (or same);
          * e must come from p. */
          e = p;
          p = irlist_get_next(p);
	  irlist_remove(list, e);
          psize--;
        } else {
          /* First element of q is lower; e must come from q. */
          e = q;
          q = irlist_get_next(q);
	  irlist_remove(list, e);
          qsize--;
        }

        /* add the next element to the merged list */
        if (tail) {
          irlist_insert_after(&newlist, e, tail);
        } else {
          list = e;
        }
        tail = e;
      }

      /* now p has stepped `insize' places along, and q has too */
      p = q;
    }

    /* If we have done only one merge, we're finished. */
    if (nmerges <= 1)   /* allow for nmerges==0, the empty list case */
      break;

    /* Otherwise repeat, merging lists twice the size */
    insize *= 2;
  }
  *list = newlist;
}
/* 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();
}
Example #26
0
static void ir_parseline2(ir_parseline_t *ipl)
{
  channel_t *ch;
  char *nick;
  char *part3a;
  char *t;
  unsigned int i;

  caps(ipl->part[1]);

  /* NOTICE nick */
  if (!strcmp(ipl->part[1], "NOTICE")) {
    if (gnetwork->caps_nick && ipl->part[2]) {
      if (!strcmp(caps(ipl->part[2]), gnetwork->caps_nick)) {
        /* nickserv */
        identify_check(ipl->line);
#ifdef USE_RUBY
        if (do_myruby_notice(ipl->line) == 0)
#endif /* USE_RUBY */
          privmsgparse(0, 0, ipl->line);
      }
    }
  }

  /* PRIVMSG */
  if (!strcmp(ipl->part[1], "PRIVMSG")) {
#ifndef WITHOUT_BLOWFISH
    char *line2;

    line2 = test_fish_message(ipl->line, ipl->part[2], ipl->part[3], ipl->part[4]);
    if (line2) {
#ifdef USE_RUBY
      if (do_myruby_privmsg(line2) == 0)
#endif /* USE_RUBY */
        privmsgparse(1, 1, line2);
      mydelete(line2);
    } else {
#endif /* WITHOUT_BLOWFISH */
#ifdef USE_RUBY
      if (do_myruby_privmsg(ipl->line) == 0)
#endif /* USE_RUBY */
        privmsgparse(1, 0, ipl->line);
#ifndef WITHOUT_BLOWFISH
    }
#endif /* WITHOUT_BLOWFISH */
  }

  /* :server 001  xxxx :welcome.... */
  if ( !strcmp(ipl->part[1], "001") ) {
    irc_001(ipl);
    return;
  }

  /* :server 005 xxxx aaa bbb=x ccc=y :are supported... */
  if ( !strcmp(ipl->part[1], "005") ) {
    irc_005(ipl);
    return;
  }

  /* :server 401 botnick usernick :No such nick/channel */
  if ( !strcmp(ipl->part[1], "401") ) {
    if (ipl->part[2] && ipl->part[3]) {
      if (!strcmp(ipl->part[2], "*")) {
        lost_nick(ipl->part[3]);
      }
    }
    return;
  }

  /* :server 433 old new :Nickname is already in use. */
  if ( !strcmp(ipl->part[1], "433") ) {
    if (ipl->part[2] && ipl->part[3]) {
      if (!strcmp(ipl->part[2], "*")) {
        ioutput(OUT_S|OUT_L, COLOR_NO_COLOR,
                "Nickname %s already in use on %s, trying %s%u",
                ipl->part[3],
                gnetwork->name,
                get_config_nick(),
                gnetwork->nick_number);

        /* generate new nick and retry */
        writeserver(WRITESERVER_NORMAL, "NICK %s%u",
                    get_config_nick(),
                    (gnetwork->nick_number)++);
      }
    }
    return;
  }

  /* :server 470 botnick #channel :(you are banned) transfering you to #newchannel */
  if ( !strcmp(ipl->part[1], "470") ) {
    if (ipl->part[2] && ipl->part[3]) {
      outerror(OUTERROR_TYPE_WARN_LOUD,
               "channel on %s: %s", gnetwork->name, strstr(ipl->line, "470"));
      for (ch = irlist_get_head(&(gnetwork->channels));
           ch;
           ch = irlist_get_next(ch)) {
        if (strcmp(caps(ipl->part[2]), gnetwork->caps_nick))
             continue;
        if (strcmp(caps(ipl->part[3]), ch->name))
             continue;
        ch->flags |= CHAN_KICKED;
      }
    }
    return;
  }

  /* names list for a channel */
  /* :server 353 our_nick = #channel :nick @nick +nick nick */
  if ( !strcmp(ipl->part[1], "353") ) {
    if (ipl->part[2] && ipl->part[3] && ipl->part[5]) {
      caps(ipl->part[4]);

      for (ch = irlist_get_head(&(gnetwork->channels));
           ch;
           ch = irlist_get_next(ch)) {
        if (strcmp(ipl->part[4], ch->name) != 0)
          continue;
        for (i=0; (t = getpart(ipl->line, 6+i)); ++i) {
          addtomemberlist(ch, i == 0 ? t+1 : t);
          mydelete(t);
        }
        return;
      }
      ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR,
              "Got name data for %s which is not a known channel on %s!",
              ipl->part[4], gnetwork->name);
      writeserver(WRITESERVER_NORMAL, "PART %s", ipl->part[4]);
    }
    return;
  }

  if (gnetwork->lastping != 0) {
    if (strcmp(ipl->part[1], "PONG") == 0) {
      lag_message();
      return;
    }
  }

#if PING_SRVR
  /* server ping */
  if (strncmp(ipl->line, "PING :", 6) == 0) {
    if (gdata.debug > 0)
      ioutput(OUT_S, COLOR_NO_COLOR,
              "Server Ping on %s: %s",
              gnetwork->name, ipl->line);
    writeserver(WRITESERVER_NOW, "PO%s", ipl->line+2);
    return;
  }
#endif

  /* QUIT */
  if (strcmp(ipl->part[1], "QUIT") == 0) {
    if (gnetwork->caps_nick) {
      nick = ir_get_nickarg(ipl->line);
      if (!strcmp(caps(nick), gnetwork->caps_nick)) {
        /* we quit? */
        outerror(OUTERROR_TYPE_WARN_LOUD,
                 "Forced quit on %s: %s", gnetwork->name, ipl->line);
        close_server();
        clean_send_buffers();
        /* do not reconnect */
        gnetwork->serverstatus = SERVERSTATUS_EXIT;
      } else {
        /* someone else quit */
        for (ch = irlist_get_head(&(gnetwork->channels));
             ch;
             ch = irlist_get_next(ch)) {
          removefrommemberlist(ch, nick);
        }
        reverify_restrictsend();
      }
      mydelete(nick);
    }
    return;
  }

  /* MODE #channel +x ... */
  if (strcmp(ipl->part[1], "MODE") == 0) {
    if (ipl->part[2] && ipl->part[3]) {
      /* find channel */
      for (ch = irlist_get_head(&(gnetwork->channels)); ch; ch = irlist_get_next(ch)) {
        char *ptr;
        unsigned int plus;
        unsigned int part;
        unsigned int ii;

        if (strcasecmp(ch->name, ipl->part[2]) != 0)
          continue;

        plus = 0;
        part = 4;
        for (ptr = ipl->part[3]; *ptr; ++ptr) {
          if (*ptr == '+') {
            plus = 1;
          } else if (*ptr == '-') {
            plus = 0;
          } else {
            for (ii = 0; (ii < MAX_PREFIX && gnetwork->prefixes[ii].p_mode); ++ii) {
              if (*ptr == gnetwork->prefixes[ii].p_mode) {
                /* found a nick mode */
                nick = getpart(ipl->line, ++part);
                if (nick) {
                  if (nick[strlen(nick)-1] == IRCCTCP) {
                    nick[strlen(nick)-1] = '\0';
                  }
                  if (plus == 0) {
                    if (strcasecmp(nick, get_config_nick()) == 0) {
                      identify_needed(0);
                    }
                  }
                  changeinmemberlist_mode(ch, nick,
                                          gnetwork->prefixes[ii].p_symbol,
                                          plus);
                  mydelete(nick);
                }
                break;
              }
            }
            for (ii = 0; (ii < MAX_CHANMODES && gnetwork->chanmodes[ii]); ++ii) {
              if (*ptr == gnetwork->chanmodes[ii]) {
                /* found a channel mode that has an argument */
                ++part;
                break;
              }
            }
          }
        }
        return;
      }
      if (strcasecmp(ipl->part[2], get_config_nick()) == 0) {
        if (ipl->part[3][0] == '-') {
          identify_needed(0);
        }
      }
    }
    return;
  }

  if (ipl->part[2] && ipl->part[2][0] == ':') {
    part3a = ipl->part[2] + 1;
  } else {
    part3a = ipl->part[2];
  }

  /* JOIN */
  if (strcmp(ipl->part[1], "JOIN") == 0) {
    if (gnetwork->caps_nick && part3a) {
      caps(part3a);
      nick = ir_get_nickarg(ipl->line);
      if (!strcmp(caps(nick), gnetwork->caps_nick)) {
        /* we joined */
        /* clear now, we have succesfully logged in */
        gnetwork->serverconnectbackoff = 0;
        ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR,
                "Joined %s on %s", part3a, gnetwork->name);

        for (ch = irlist_get_head(&(gnetwork->channels));
             ch;
             ch = irlist_get_next(ch)) {
          if (strcmp(part3a, ch->name) != 0)
            continue;

          ch->flags |= CHAN_ONCHAN;
          ch->lastjoin = gdata.curtime;
          ch->nextann = gdata.curtime + gdata.waitafterjoin;
          ch->nextmsg = gdata.curtime + gdata.waitafterjoin;
          if (ch->joinmsg) {
            writeserver(WRITESERVER_NOW, "PRIVMSG %s :%s", ch->name, ch->joinmsg);
          }
          gnetwork->botstatus = BOTSTATUS_JOINED;
          start_sends();
          mydelete(nick);
          return;
        }
      } else {
        /* someone else joined */
        for (ch = irlist_get_head(&(gnetwork->channels));
             ch;
             ch = irlist_get_next(ch)) {
          if (strcmp(part3a, ch->name) != 0)
            continue;

          addtomemberlist(ch, nick);
          mydelete(nick);
          return;
        }
      }
      ir_unknown_channel(part3a);
      mydelete(nick);
    }
    return;
  }

  /* PART */
  if (strcmp(ipl->part[1], "PART") == 0) {
    if (gnetwork->caps_nick && part3a) {
      nick = ir_get_nickarg(ipl->line);
      if (!strcmp(caps(nick), gnetwork->caps_nick)) {
        /* we left? */
        mydelete(nick);
        return;
      } else {
        /* someone else left */
        caps(part3a);
        for (ch = irlist_get_head(&(gnetwork->channels));
             ch;
             ch = irlist_get_next(ch)) {
          if (strcmp(part3a, ch->name) != 0)
            continue;

          removefrommemberlist(ch, nick);
          mydelete(nick);
          reverify_restrictsend();
          return;
        }
      }
      ir_unknown_channel(part3a);
      mydelete(nick);
    }
    return;
  }

  /* NICK */
  if (strcmp(ipl->part[1], "NICK") == 0) {
    if (gnetwork->caps_nick && part3a) {
      nick = ir_get_nickarg(ipl->line);
      if (!strcmp(caps(nick), gnetwork->caps_nick)) {
        /* we changed, update nick */
        mydelete(gnetwork->user_nick);
        mydelete(gnetwork->caps_nick);
        gnetwork->user_nick = mystrdup(part3a);
        gnetwork->caps_nick = mystrdup(part3a);
        caps(gnetwork->caps_nick);
        gnetwork->nick_number = 0;
        ++(gdata.needsclear);
        identify_needed(0);
      } else {
        /* someone else has a new nick */
        for (ch = irlist_get_head(&(gnetwork->channels));
             ch;
             ch = irlist_get_next(ch)) {
          changeinmemberlist_nick(ch, nick, part3a);
        }
        user_changed_nick(nick, part3a);
      }
      mydelete(nick);
    }
    return;
  }

  /* KICK */
  if (strcmp(ipl->part[1], "KICK") == 0) {
    if (gnetwork->caps_nick && part3a && ipl->part[3]) {
      caps(part3a);
      if (!strcmp(caps(ipl->part[3]), gnetwork->caps_nick)) {
        /* we were kicked */
        for (ch = irlist_get_head(&(gnetwork->channels));
             ch;
             ch = irlist_get_next(ch)) {
          if (strcmp(part3a, ch->name) != 0)
            continue;

          if (gdata.noautorejoin) {
            outerror(OUTERROR_TYPE_WARN_LOUD,
                     "Kicked on %s: %s", gnetwork->name, ipl->line);
            ch->flags |= CHAN_KICKED;
            clearmemberlist(ch);
            reverify_restrictsend();
          } else {
            outerror(OUTERROR_TYPE_WARN_LOUD,
                     "Kicked on %s, Rejoining: %s", gnetwork->name, ipl->line);
            ch->flags &= ~CHAN_ONCHAN;
            joinchannel(ch);
          }
        }
      } else {
        /* someone else was kicked */
        for (ch = irlist_get_head(&(gnetwork->channels));
             ch;
             ch = irlist_get_next(ch)) {
          if (strcmp(part3a, ch->name) != 0)
            continue;

          removefrommemberlist(ch, ipl->part[3]);
          reverify_restrictsend();
          return;
        }
      }
    }
    return;
  }

  /* ERROR :Closing Link */
  if (strncmp(ipl->line, "ERROR :Closing Link", strlen("ERROR :Closing Link")) == 0) {
    if (gdata.exiting) {
      gnetwork->recentsent = 0;
      return;
    }
    ioutput(OUT_S|OUT_L|OUT_D, COLOR_RED,
            "Server Closed Connection on %s: %s",
            gnetwork->name, ipl->line);
    close_server();
    return;
  }
}
Example #27
0
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;
}
Example #28
0
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();
     }
   
   }
Example #29
0
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(&timestruct, NULL);
        last250ms = gdata.curtimems;
        gdata.curtimems = timeval_to_ms(&timestruct);
        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(&timestruct, NULL);
    gdata.selecttimems = timeval_to_ms(&timestruct);
    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(&timestruct, NULL) < 0)
    {
        outerror(OUTERROR_TYPE_CRASH,"gettimeofday() failed! %s\n",strerror(errno));
    }

    gdata.curtimems = timeval_to_ms(&timestruct);
    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;

}
/* 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();
}