/* match a given file against a list of required patterns */
unsigned int no_verifyshell(irlist_t *list, const char *file)
{
  if (irlist_size(list)) {
    if (!verifyshell(list, file))
      return 1;
  }
  return 0;
}
/* select a transfer to start with */
static unsigned int select_starting_transfer(void)
{
    unsigned int t;

    t = gdata.cursendptr;
    if (++t >= irlist_size(&gdata.trans))
        t = 0;
    gdata.cursendptr = t;
    return ++t;
}
/* check ip for matching blacklist and whitelist */
unsigned int t_check_ip_access(transfer *const tr)
{
    const char *msg;
    if (irlist_size(&gdata.xdcc_allow) > 0) {
        if (!verify_cidr(&gdata.xdcc_allow, &(tr->con.remote))) {
            msg = "Sorry, downloads to your IP not allowed, ask owner.";
            t_closeconn(tr, msg, 0);
            ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "%s", msg);
            return 1;
        }
    }

    if (verify_cidr(&gdata.xdcc_deny, &(tr->con.remote))) {
        msg = "Sorry, downloads to your IP denied, ask owner.";
        t_closeconn(tr, msg, 0);
        ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "%s", msg);
        return 1;
    }
    return 0;
}
/* 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;
}
/* 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;
}
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();
    }
}
/* check if a file is already in transfer */
unsigned int fetch_running(void)
{
  return irlist_size(&fetch_trans);
}
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;

}
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();
     }
   
   }
void parsedccchat(dccchat_t *chat,
                  char* line)
{
  char *linec;
  userinput ui;
  unsigned int count;
  unsigned int found;
  
  updatecontext();
  
  linec = mystrdup(line);
  caps(linec);
  
  chat->con.lastcontact = gdata.curtime;
  
  switch (chat->status)
    {
    case DCCCHAT_AUTHENTICATING:
      found = dcc_host_password(chat, line);
      if (found == 1)
        {
          ioutput(OUT_S|OUT_L|OUT_D, COLOR_MAGENTA,
                  "DCC CHAT Correct password");
          
          chat->status = DCCCHAT_CONNECTED;
          
          writedccchat(chat,0," \n");
          writedccchat(chat,0,"Entering DCC Chat Admin Interface\n");
          writedccchat(chat,0,"For Help type \"help\"\n");
          
          if (chat->level >= ADMIN_LEVEL_FULL)
            {
          count = irlist_size(&gdata.msglog);
          writedccchat(chat, 0, "** You have %u %s in the message log%s\n",
                       count,
                       count != 1 ? "messages" : "message",
                       count ? ", use MSGREAD to read them" : "");
          writedccchat(chat,0," \n");
            }
        }
      else
        {
          ioutput(OUT_S|OUT_L|OUT_D, COLOR_MAGENTA,
                  "DCC CHAT: Incorrect password");
          
          writedccchat(chat,0,"Incorrect Password\n");
          count_badip(&(chat->con.remote));
          shutdowndccchat(chat,1);
          /* caller deletes */
        }
      break;
      
    case DCCCHAT_CONNECTED:
      if (gdata.debug > 11)
        {
          ioutput(OUT_S, COLOR_CYAN, ">DCC>: %s", line);
        }
      u_fillwith_dcc(&ui,chat,line);
      u_parseit(&ui);
      break;
      
    case DCCCHAT_UNUSED:
    case DCCCHAT_LISTENING:
    case DCCCHAT_CONNECTING:
    default:
      outerror(OUTERROR_TYPE_WARN_LOUD,
               "Unexpected dccchat state %u", chat->status);
      break;
    }
  
  mydelete(linec);
}
Beispiel #11
0
/* accept incoming connection */
static void telnet_accept(unsigned int i)
{
  gnetwork_t *backup;
  char *msg;
  dccchat_t *chat;
  SIGNEDSOCK int addrlen;

  updatecontext();

  chat = irlist_add(&gdata.dccchats, sizeof(dccchat_t));
  chat->name = "telnet"; /* NOTRANSLATE */
  chat->status = DCCCHAT_UNUSED;
  chat->con.family = telnet_family[i];
  if (chat->con.family != AF_INET) {
    addrlen = sizeof (struct sockaddr_in6);
    chat->con.clientsocket = accept(telnet_listen[i], &(chat->con.remote.sa), &addrlen);
  } else {
    addrlen = sizeof (struct sockaddr_in);
    chat->con.clientsocket = accept(telnet_listen[i], &(chat->con.remote.sa), &addrlen);
  }
  if (chat->con.clientsocket < 0) {
    outerror(OUTERROR_TYPE_WARN, "Accept Error, Aborting: %s", strerror(errno));
    return;
  }

  if (set_socket_nonblocking(chat->con.clientsocket, 1) < 0 ) {
    outerror(OUTERROR_TYPE_WARN, "Couldn't Set Non-Blocking");
  }

  addrlen = sizeof(chat->con.local);
  if (getsockname(chat->con.clientsocket, &(chat->con.local.sa), &addrlen) < 0) {
    outerror(OUTERROR_TYPE_WARN_LOUD, "Couldn't get sock name: %s", strerror(errno));
    shutdown_close(chat->con.clientsocket);
    chat->con.clientsocket = FD_UNUSED;
    return;
  }

  ++(gdata.num_dccchats);
  chat->status = DCCCHAT_AUTHENTICATING;
  chat->net = 0;
  chat->nick = mystrdup("telnet"); /* NOTRANSLATE */
  chat->hostmask = to_hostmask(chat->nick, "telnet"); /* NOTRANSLATE */
  chat->con.localport = gdata.telnet_port;
  chat->con.connecttime = gdata.curtime;
  chat->con.lastcontact = gdata.curtime;

  msg = mymalloc(maxtextlength);
  my_getnameinfo(msg, maxtextlength -1, &(chat->con.remote.sa));
  chat->con.localaddr = mystrdup(msg);
  my_getnameinfo(msg, maxtextlength -1, &(chat->con.local.sa));
  chat->con.remoteaddr = mystrdup(msg);
  ioutput(OUT_S|OUT_L|OUT_D, COLOR_MAGENTA,
          "Telnet connection received from %s",  msg);
  mydelete(msg);

  if (is_in_badip(&(chat->con.remote))) {
    shutdowndccchat(chat, 0);
    return;
  }

  if (irlist_size(&gdata.telnet_allow) > 0) {
    if (!verify_cidr(&gdata.telnet_allow, &(chat->con.remote))) {
      shutdowndccchat(chat, 0);
      return;
    }
  }

  if (verify_cidr(&gdata.telnet_deny, &(chat->con.remote))) {
    shutdowndccchat(chat, 0);
    return;
  }

  ir_boutput_init(&chat->boutput, chat->con.clientsocket, 0);

  backup = gnetwork;
  gnetwork = &(gdata.networks[chat->net]);
  setup_chat_banner(chat);
  gnetwork = backup;
}
Beispiel #12
0
static VALUE cie_info_pack(VALUE UNUSED(module), VALUE rnr, VALUE rkey)
{
  xdcc *xd;
  const char *key;
  const char *val;
  char *tempstr;
  unsigned int nr;
  unsigned int ival;
  off_t oval;
  size_t len;
  VALUE rval;

  if (NIL_P(rnr) || NIL_P(rkey))
    return Qnil;

  nr = FIX2UINT(rnr);
  if (nr == 0)
    return Qnil;

  if (nr > irlist_size(&gdata.xdccs))
    return Qnil;

  xd = get_xdcc_pack(nr);
  if (xd == NULL)
    return Qnil;

  key = rb_obj_as_string_protected(rkey);
  if (!key)
    return Qnil;

  for (;;) {
    if (strcmp(key, "file") == 0) { /* NOTRANSLATE */
      val = xd->file;
      break;
    }
    if (strcmp(key, "name") == 0) { /* NOTRANSLATE */
      val = getfilename(xd->file);
      break;
    }
    if (strcmp(key, "desc") == 0) { /* NOTRANSLATE */
      val = xd->desc;
      break;
    }
    if (strcmp(key, "note") == 0) { /* NOTRANSLATE */
      val = xd->note;
      break;
    }
    if (strcmp(key, "group") == 0) { /* NOTRANSLATE */
      val = xd->group;
      break;
    }
    if (strcmp(key, "group_desc") == 0) { /* NOTRANSLATE */
      val = find_groupdesc(xd->group);
      break;
    }
    if (strcmp(key, "trigger") == 0) { /* NOTRANSLATE */
      val = xd->trigger;
      break;
    }
    if (strcmp(key, "lock") == 0) { /* NOTRANSLATE */
      val = xd->lock;
      break;
    }
    if (strcmp(key, "gets") == 0) { /* NOTRANSLATE */
      ival = xd->gets;
      return UINT2NUM(ival);
    }
    if (strcmp(key, "color") == 0) { /* NOTRANSLATE */
      ival = xd->color;
      return UINT2NUM(ival);
    }
    if (strcmp(key, "dlimit_max") == 0) { /* NOTRANSLATE */
      ival = xd->dlimit_max;
      return UINT2NUM(ival);
    }
    if (strcmp(key, "dlimit_used") == 0) { /* NOTRANSLATE */
      ival = xd->dlimit_used;
      return UINT2NUM(ival);
    }
    if (strcmp(key, "has_md5sum") == 0) { /* NOTRANSLATE */
      ival = xd->has_md5sum;
      return UINT2NUM(ival);
    }
    if (strcmp(key, "has_crc32") == 0) { /* NOTRANSLATE */
      ival = xd->has_crc32;
      return UINT2NUM(ival);
    }
    if (strcmp(key, "bytes") == 0) { /* NOTRANSLATE */
      oval = xd->st_size;
      return OFFT2NUM(oval);
    }
    if (strcmp(key, "size") == 0) { /* NOTRANSLATE */
      tempstr = sizestr(0, xd->st_size);
      len = strlen(tempstr);
      rval = rb_str_new(tempstr, len);
      mydelete(tempstr);
      return rval;
    }
    if (strcmp(key, "mtime") == 0) { /* NOTRANSLATE */
      return rb_time_new(xd->mtime, 0);
    }
    if (strcmp(key, "xtime") == 0) { /* NOTRANSLATE */
      return rb_time_new(xd->xtime, 0);
    }
    if (strcmp(key, "crc32") == 0) { /* NOTRANSLATE */
      tempstr = mymalloc(maxtextlengthshort);
      len = add_snprintf(tempstr, maxtextlengthshort, CRC32_PRINT_FMT, xd->crc32);
      rval = rb_str_new(tempstr, len);
      mydelete(tempstr);
      return rval;
    }
    if (strcmp(key, "md5sum") == 0) { /* NOTRANSLATE */
      tempstr = mymalloc(maxtextlengthshort);
      len = add_snprintf(tempstr, maxtextlengthshort, MD5_PRINT_FMT, MD5_PRINT_DATA(xd->md5sum));
      rval = rb_str_new(tempstr, len);
      mydelete(tempstr);
      return rval;
    }
    /* minspeed, maxspeed */
    return Qnil;
  }
  if (val == NULL)
    return Qnil;
  return rb_str_new(val, strlen(val));
}
unsigned int read_statefile(void)
{
  int fd;
  ir_uint32 *buffer, *buffer_begin;
  ir_uint32 buffer_len;
  struct MD5Context md5sum;
  MD5Digest digest;
  struct stat st;
  statefile_hdr_t *hdr;
  ir_uint32 calluval;
  unsigned int save = 0;
  time_t timestamp = 0;
  
  updatecontext();
  
  if (gdata.statefile == NULL)
    {
      return save;
    }
  
  ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Loading State File... ");
  
  fd = open(gdata.statefile,
            O_RDONLY | O_CREAT | ADDED_OPEN_FLAGS,
            CREAT_PERMISSIONS );
  
  if (fd < 0)
    {
      outerror(OUTERROR_TYPE_WARN_LOUD, "Cant Access State File '%s': %s",
               gdata.statefile, strerror(errno));
      return ++save;
    }
  
  if ((fstat(fd, &st) < 0) || (st.st_size < ((off_t)(sizeof(ir_uint32) * 2) + (off_t)(sizeof(MD5Digest)))))
    {
      ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "State File: Too small, Skipping");
      close(fd);
      return ++save;
    }
  
  buffer_len = st.st_size;
  buffer_begin = buffer = mycalloc(buffer_len);
  
  calluval = read(fd, buffer, buffer_len);
  close(fd);
  if (calluval != buffer_len)
    {
      outerror(OUTERROR_TYPE_WARN_LOUD, "Cant Read State File (%u != %u) %s",
               calluval, buffer_len, strerror(errno));
      goto error_out;
    }
  
  /* verify md5sum */
  buffer_len -= sizeof(MD5Digest);
  
  MD5Init(&md5sum);
  MD5Update(&md5sum, (md5byte*)buffer, buffer_len);
  MD5Final(digest, &md5sum);
  
  if (memcmp(digest, buffer+(buffer_len/sizeof(ir_uint32)), sizeof(MD5Digest)))
    {
      outerror(OUTERROR_TYPE_CRASH,
               "\"%s\" Appears corrupt or is not an iroffer state file",
               gdata.statefile);
      goto error_out;
    }
  
  /* read */
  
  if (ntohl(*buffer) != STATEFILE_MAGIC)
    {
      outerror(OUTERROR_TYPE_CRASH,
               "\"%s\" Does not appear to be an iroffer state file",
               gdata.statefile);
      goto error_out;
    }
  buffer++;
  buffer_len -= sizeof(ir_uint32);
  
  if (gdata.debug > 0)
    {
      ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR,
              "  [Version %u State File]", ntohl(*buffer));
    }
  buffer++;
  buffer_len -= sizeof(ir_uint32);
  
  while ((hdr = read_statefile_item(&buffer, &buffer_len)))
    {
      switch (hdr->tag)
        {
        case STATEFILE_TAG_TIMESTAMP:
          read_statefile_time(hdr, "Timestamp", &timestamp, "Written on");
          break;
          
        case STATEFILE_TAG_XFR_RECORD:
          read_statefile_float(hdr, "xfr Record", &(gdata.record), "Record");
          break;
          
        case STATEFILE_TAG_SENT_RECORD:
          read_statefile_float(hdr, "sent Record", &(gdata.sentrecord), "Bandwidth Record");
          break;
          
        case STATEFILE_TAG_TOTAL_SENT:
          read_statefile_llint(hdr, "Total Transferred", &(gdata.totalsent), "Total Transferred");
          break;
          
        case STATEFILE_TAG_TOTAL_UPTIME:
          read_statefile_long(hdr, "Total Runtime", &(gdata.totaluptime));
              if (gdata.debug > 0)
                {
                  char *tempstr;
                  tempstr = mymalloc(maxtextlength);
                  getuptime(tempstr, 0, gdata.curtime-gdata.totaluptime, maxtextlength);
                  ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR,
                          "  [Total Runtime %s]", tempstr);
                  mydelete(tempstr);
                }
          break;
          
        case STATEFILE_TAG_LAST_LOGROTATE:
          read_statefile_time(hdr, "Last Log Rotate", &(gdata.last_logrotate), "Last Log Rotate");
          break;
          
        case STATEFILE_TAG_IROFFER_VERSION:
          if (hdr->length > sizeof(statefile_hdr_t))
            {
              char *iroffer_version = (char*)(&hdr[1]);
              char *iroffer_now;
              iroffer_version[hdr->length-sizeof(statefile_hdr_t)-1] = '\0';
              
              if (gdata.debug > 0)
                {
                  ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR,
                          "  [Written by %s]", iroffer_version);
                }
              iroffer_now = mycalloc(maxtextlength);
              snprintf(iroffer_now, maxtextlength, "iroffer-dinoex " VERSIONLONG ", %s", gdata.osstring);
              if (strcmp(iroffer_version, iroffer_now) != 0)
                {
                  ++save;
                  backup_statefile();
                }
              mydelete(iroffer_now);
            }
          else
            {
              read_statefile_bad_tag(hdr, "Iroffer Version");
            }
          break;
          
        case STATEFILE_TAG_IGNORE:
          {
            igninfo *ignore;
            statefile_hdr_t *ihdr;

            ignore = irlist_add(&gdata.ignorelist, sizeof(igninfo));
            
            hdr->length -= sizeof(*hdr);
            ihdr = &hdr[1];
            
            while (hdr->length >= sizeof(*hdr))
              {
                ihdr->tag = ntohl(ihdr->tag);
                ihdr->length = ntohl(ihdr->length);
                switch (ihdr->tag)
                  {
                  case STATEFILE_TAG_IGNORE_FLAGS:
                    read_statefile_int(ihdr, "Ignore Flags", &(ignore->flags));
                    break;
                    
                  case STATEFILE_TAG_IGNORE_BUCKET:
                    read_statefile_long(ihdr, "Ignore Bucket", &(ignore->bucket));
                    break;
                    
                  case STATEFILE_TAG_IGNORE_LASTCONTACT:
                    read_statefile_time(ihdr, "Ignore Lastcontact", &(ignore->lastcontact), NULL);
                    break;
                    
                  case STATEFILE_TAG_IGNORE_HOSTMASK:
                    read_statefile_string(ihdr, "Ignore Hostmask", &(ignore->hostmask));
                    break;
                    
                  default:
                    read_statefile_unknown_tag(ihdr, "Ignore" );
                  }
                hdr->length -= ceiling(ihdr->length, 4);
                ihdr = (statefile_hdr_t*)(((char*)ihdr) + ceiling(ihdr->length, 4));
              }
            
            if ((!ignore->lastcontact) || (!ignore->hostmask))
              {
                read_statefile_incomplete_tag("Ignore" );
                mydelete(ignore->hostmask);
                irlist_delete(&gdata.ignorelist, ignore);
              }
            else
              {
                ignore->bucket -= (gdata.curtime - timestamp)/gdata.autoignore_threshold;
              }
          }
          
          break;
          
        case STATEFILE_TAG_MSGLOG:
          {
            msglog_t *msglog;
            statefile_hdr_t *ihdr;

            msglog = irlist_add(&gdata.msglog, sizeof(msglog_t));
            
            hdr->length -= sizeof(*hdr);
            ihdr = &hdr[1];
            
            while (hdr->length >= sizeof(*hdr))
              {
                ihdr->tag = ntohl(ihdr->tag);
                ihdr->length = ntohl(ihdr->length);
                switch (ihdr->tag)
                  {
                  case STATEFILE_TAG_MSGLOG_WHEN:
                    read_statefile_time(ihdr, "Msglog When", &(msglog->when), NULL);
                    break;
                    
                  case STATEFILE_TAG_MSGLOG_HOSTMASK:
                    read_statefile_string(ihdr, "Msglog Hostmask", &(msglog->hostmask));
                    break;
                    
                  case STATEFILE_TAG_MSGLOG_MESSAGE:
                    read_statefile_string(ihdr, "Msglog Message", &(msglog->message));
                    break;
                    
                  default:
                    read_statefile_unknown_tag(ihdr, "Msglog" );
                  }
                hdr->length -= ceiling(ihdr->length, 4);
                ihdr = (statefile_hdr_t*)(((char*)ihdr) + ceiling(ihdr->length, 4));
              }
            
            if ((!msglog->when) || (!msglog->hostmask) || (!msglog->message))
              {
                read_statefile_incomplete_tag("Msglog" );
                mydelete(msglog->hostmask);
                mydelete(msglog->message);
                irlist_delete(&gdata.msglog, msglog);
              }
          }
          
          break;
          
        case STATEFILE_TAG_XDCCS:
          {
            xdcc *xd;
            statefile_hdr_t *ihdr;
            
            xd = irlist_add(&gdata.xdccs, sizeof(xdcc));
            xd->file_fd = FD_UNUSED;
            
            xd->minspeed = gdata.transferminspeed;
            xd->maxspeed = gdata.transfermaxspeed;
            
            hdr->length -= sizeof(*hdr);
            ihdr = &hdr[1];
            
            while (hdr->length >= sizeof(*hdr))
              {
                ihdr->tag = ntohl(ihdr->tag);
                ihdr->length = ntohl(ihdr->length);
                switch (ihdr->tag)
                  {
                  case STATEFILE_TAG_XDCCS_FILE:
                    read_statefile_string(ihdr, "XDCC File", &(xd->file));
                    xd->desc = mystrdup(getfilename(xd->file));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_DESC:
                    mydelete(xd->desc);
                    read_statefile_string(ihdr, "XDCC Desc", &(xd->desc));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_NOTE:
                    read_statefile_string(ihdr, "XDCC Note", &(xd->note));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_GETS:
                    read_statefile_int(ihdr, "XDCC Gets", &(xd->gets));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_MINSPEED:
                    read_statefile_float_set(ihdr, "XDCC Minspeed", &(xd->minspeed));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_MAXSPEED:
                    read_statefile_float_set(ihdr, "XDCC Maxspeed", &(xd->maxspeed));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_MD5SUM_INFO:
                    read_statefile_md5info(ihdr, "XDCC md5sum", xd);
                    break;
                    
                  case STATEFILE_TAG_XDCCS_CRC32:
                    read_statefile_int(ihdr, "XDCC CRC32", &(xd->crc32));
                    xd->has_crc32 = 1;
                    break;
                    
                  case STATEFILE_TAG_XDCCS_GROUP:
                    read_statefile_string(ihdr, "XDCC Group", &(xd->group));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_GROUP_DESC:
                    read_statefile_string(ihdr, "XDCC Group Desc", &(xd->group_desc));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_LOCK:
                    read_statefile_string(ihdr, "XDCC Lock", &(xd->lock));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_DLIMIT_MAX:
                    read_statefile_int(ihdr, "XDCC Limit Max", &(xd->dlimit_max));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_DLIMIT_USED:
                    read_statefile_int(ihdr, "XDCC Limit Used", &(xd->dlimit_used));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_DLIMIT_DESC:
                    read_statefile_string(ihdr, "XDCC Limit Desc", &(xd->dlimit_desc));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_TRIGGER:
                    read_statefile_string(ihdr, "XDCC Trigger", &(xd->trigger));
                    break;
                    
                  case STATEFILE_TAG_XDCCS_XTIME:
                    read_statefile_time(ihdr, "XDCC Time", &(xd->xtime), NULL);
                    break;

                  case STATEFILE_TAG_XDCCS_COLOR:
                    read_statefile_int(ihdr, "XDCC Color", &(xd->color));
                    break;
                    
                  default:
                    read_statefile_unknown_tag(ihdr, "XDCC" );
                  }
                hdr->length -= ceiling(ihdr->length, 4);
                ihdr = (statefile_hdr_t*)(((char*)ihdr) + ceiling(ihdr->length, 4));
              }
            
            if ((!xd->file) || (!xd->desc))
              {
                read_statefile_incomplete_tag("XDCC" );
                mydelete(xd->file);
                mydelete(xd->desc);
                mydelete(xd->note);
                mydelete(xd->group);
                mydelete(xd->group_desc);
                mydelete(xd->lock);
                mydelete(xd->trigger);
                irlist_delete(&gdata.xdccs, xd);
              }
            else
              {
                if (stat(xd->file, &st) < 0)
                  {
                    outerror(OUTERROR_TYPE_WARN, "Pack %u: Cant Access Offered File '%s': %s",
                             number_of_pack(xd),
                             xd->file, strerror(errno));
                    memset(&st, 0, sizeof(st));
                    break;
                  }
                if (!xd->has_md5sum ||
                    (xd->st_ino   != st.st_ino) ||
                    (xd->mtime    != st.st_mtime) ||
                    (xd->st_size  != st.st_size))
                  {
                    xd->st_size     = st.st_size;
                    xd->st_dev      = st.st_dev;
                    xd->st_ino      = st.st_ino;
                    xd->mtime       = st.st_mtime;
                    xd->has_md5sum  = 0;
                    memset(xd->md5sum, 0, sizeof(MD5Digest));
                  }
                if (xd->st_dev != st.st_dev)
                  {
                    /* only mountpoint has changed */
                    xd->st_dev = st.st_dev;
                  }
                
                if (xd->st_size == 0)
                  {
                    outerror(OUTERROR_TYPE_WARN, "Pack %u: The file \"%s\" has size of 0 byte!",
                             number_of_pack(xd),
                             xd->file);
                  }
                
                if (xd->st_size > gdata.max_file_size)
                  {
                    outerror(OUTERROR_TYPE_CRASH, "Pack %u: The file \"%s\" is too large!",
                             number_of_pack(xd),
                             xd->file);
                  }
              }
          }
          
          break;
          
        case STATEFILE_TAG_TLIMIT_DAILY_USED:
          read_statefile_llint(hdr, "Daily Transfer Limit Used", &(gdata.transferlimits[TRANSFERLIMIT_DAILY].used), "Daily Transfer Limit Used");
          break;
          
        case STATEFILE_TAG_TLIMIT_DAILY_ENDS:
          read_statefile_time(hdr, "Daily Transfer Limit Ends", &(gdata.transferlimits[TRANSFERLIMIT_DAILY].ends), "Daily Transfer Limit Ends");
          break;
          
        case STATEFILE_TAG_TLIMIT_WEEKLY_USED:
          read_statefile_llint(hdr, "Weekly Transfer Limit Used", &(gdata.transferlimits[TRANSFERLIMIT_WEEKLY].used), "Weekly Transfer Limit Used");
          break;
          
        case STATEFILE_TAG_TLIMIT_WEEKLY_ENDS:
          read_statefile_time(hdr, "Weekly Transfer Limit Ends", &(gdata.transferlimits[TRANSFERLIMIT_WEEKLY].ends), "Weekly Transfer Limit Ends");
          break;
          
        case STATEFILE_TAG_TLIMIT_MONTHLY_USED:
          read_statefile_llint(hdr, "Monthly Transfer Limit Used", &(gdata.transferlimits[TRANSFERLIMIT_MONTHLY].used), "Monthly Transfer Limit Used");
          break;
          
        case STATEFILE_TAG_TLIMIT_MONTHLY_ENDS:
          read_statefile_time(hdr, "Monthly Transfer Limit Ends", &(gdata.transferlimits[TRANSFERLIMIT_MONTHLY].ends), "Monthly Transfer Limit Ends");
          break;
          
        case STATEFILE_TAG_QUEUE:
          read_statefile_queue(hdr);
          break;
          
        default:
          read_statefile_unknown_tag(hdr, "Main" );
          break;
        }
    }
  
  if (buffer_len)
    {
      outerror(OUTERROR_TYPE_WARN, "Extra data at end of state file!? %u left",
               buffer_len);
    }
  
  /* end read */
  
  if ((gdata.debug > 0) || irlist_size(&gdata.ignorelist))
    {
      ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "  [Found %u %s]",
              irlist_size(&gdata.ignorelist),
              (irlist_size(&gdata.ignorelist) == 1) ? "ignore" : "ignores");
    }
  
  if ((gdata.debug > 0) || irlist_size(&gdata.msglog))
    {
      ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "  [Found %u %s]",
              irlist_size(&gdata.msglog),
              (irlist_size(&gdata.msglog) == 1) ? "message" : "messages");
    }
  
  if ((gdata.debug > 0) || irlist_size(&gdata.xdccs))
    {
      ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "  [Found %u %s]",
              irlist_size(&gdata.xdccs),
              (irlist_size(&gdata.xdccs) == 1) ? "pack" : "packs");
    }
  
  if ((gdata.debug > 0) || irlist_size(&gdata.mainqueue))
    {
      ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "  [Found %u %s]",
              irlist_size(&gdata.mainqueue),
              (irlist_size(&gdata.mainqueue) == 1) ? "queue" : "queues");
    }
  if ((gdata.debug > 0) || irlist_size(&gdata.idlequeue))
    {
      ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "  [Found %u %s]",
              irlist_size(&gdata.idlequeue),
              (irlist_size(&gdata.idlequeue) == 1) ? "queue" : "queues");
    }
  
  ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "  [Done]");
  
 error_out:
  
  mydelete(buffer_begin);
  
  return save;
}