/*
 * by Dirk Meyer (dinoex)
 * Copyright (C) 2004-2007 Dirk Meyer
 * 
 * By using this file, you agree to the terms and conditions set
 * forth in the GNU General Public License.  More information is    
 * available in the README file.
 * 
 * If you received this file without documentation, it can be
 * downloaded from http://iroffer.dinoex.net/
 * 
 * $Id: dinoex_misc.c,v 1.4 2007/07/08 08:38:11 dinoex Exp $
 * 
 */

/* include the headers */
#include "iroffer_config.h"
#include "iroffer_defines.h"
#include "iroffer_headers.h"
#include "iroffer_globals.h"
#include "dinoex_utilities.h"
#include "dinoex_admin.h"
#include "dinoex_misc.h"

#include <ctype.h>

static void admin_line(int fd, const char *line) {
   userinput *uxdl;
   char *full;
   
   if (line == NULL)
      return;
   
   uxdl = mycalloc(sizeof(userinput));
   full = mycalloc(maxtextlength);

   snprintf(full,maxtextlength -1,"A A A A A %s", line);
   u_fillwith_msg(uxdl,NULL,full);
   uxdl->method = method_fd;
   uxdl->fd = fd;
   u_parseit(uxdl);
   
   mydelete(uxdl);
   mydelete(full);
}

static void admin_run(const char *cmd) {
   int fd;
   const char *job;
   char *done;
   
   job = gdata.admin_job_file;
   if (job == NULL)
      return;

   done = mycalloc(strlen(job)+6);
   strcpy(done,job);
   strcat(done,".done");
   fd = open(done,
             O_WRONLY | O_CREAT | O_APPEND | ADDED_OPEN_FLAGS,
             CREAT_PERMISSIONS);
   if (fd < 0)
    {
      outerror(OUTERROR_TYPE_WARN_LOUD,
               "Cant Create Admin Job Done File '%s': %s",
               done, strerror(errno));
    }
  else
    {
      admin_line(fd, cmd);
      close(fd);
    }
   mydelete(done)
}

void admin_jobs(void) {
   FILE *fin;
   const char *job;
   char *line;
   char *l;
   char *r;
   
   job = gdata.admin_job_file;
   if (job == NULL)
      return;

   fin = fopen(job, "ra" );
   if (fin == NULL)
      return;

   line = mycalloc(maxtextlength);
   while (!feof(fin)) {
      r = fgets(line, maxtextlength - 1, fin);
      if (r == NULL )
         break;
      l = line + strlen(line) - 1;
      while (( *l == '\r' ) || ( *l == '\n' ))
         *(l--) = 0;
      admin_run(line);
   }
   mydelete(line)
   fclose(fin);
   unlink(job);
}


int hide_pack(const xdcc *xd)
{
  if (gdata.hidelockedpacks == 0)
    return 0;
  
  if (xd->lock == NULL)
    return 0;
  
  return 1;
}

int check_lock(const char* lockstr, const char* pwd)
{
  if (lockstr == NULL)
    return 0; /* no lock */
  if (pwd == NULL)
    return 1; /* locked */
  return strcmp(lockstr, pwd);
}

void update_natip (const char *var)
{
  struct hostent *hp;
  struct in_addr old;
  struct in_addr in;
  long oldip;
  char *oldtxt;

  if (var == NULL)
    return;

  gdata.usenatip = 1;
  if (gdata.r_ourip != 0)
    return;

  bzero((char *)&in, sizeof(in));
  if (inet_aton(var, &in) == 0)
    {
      hp = gethostbyname(var);
      if (hp == NULL)
        {
          outerror(OUTERROR_TYPE_WARN_LOUD,"Invalid NAT Host, Ignoring: %s",hstrerror(h_errno));
          return;
        }
      if ((unsigned)hp->h_length > sizeof(in) || hp->h_length < 0)
        {
          outerror(OUTERROR_TYPE_WARN_LOUD,"Invalid DNS response, Ignoring: %s",hstrerror(h_errno));
          return;
        }
      memcpy(&in, hp->h_addr_list[0], sizeof(in));
    }
 
  old.s_addr = htonl(gdata.ourip);
  if (old.s_addr == in.s_addr)
    return;

  oldip = gdata.ourip;
  gdata.ourip = ntohl(in.s_addr);
  if (oldip != 0 )
    {
      oldtxt = mystrdup(inet_ntoa(old));
      ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_YELLOW,
              "DCC IP changed from %s to %s", oldtxt, inet_ntoa(in));
      mydelete(oldtxt);
    }
 
  if (gdata.debug > 0) ioutput(CALLTYPE_NORMAL,OUT_S,COLOR_YELLOW,"ip=0x%8.8lX\n",gdata.ourip);

  /* check for 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 */
  if (((gdata.ourip & 0xFF000000UL) == 0x0A000000UL) ||
      ((gdata.ourip & 0xFFF00000UL) == 0xAC100000UL) ||
      ((gdata.ourip & 0xFFFF0000UL) == 0xC0A80000UL))
    {
      outerror(OUTERROR_TYPE_WARN_LOUD,"usenatip of %lu.%lu.%lu.%lu looks wrong, this is probably not what you want to do",
                (gdata.ourip >> 24) & 0xFF,
                (gdata.ourip >> 16) & 0xFF,
                (gdata.ourip >>  8) & 0xFF,
                (gdata.ourip      ) & 0xFF);
     }
}

void stoplist(const char *nick)
{
  char *item;
  char *copy;
  char *end;
  char *inick;
  int stopped = 0;
  
  ioutput(CALLTYPE_MULTI_FIRST, OUT_S|OUT_L|OUT_D, COLOR_YELLOW,
          "XDCC STOP from (%s)", nick);
  item = irlist_get_head(&(gdata.xlistqueue));
  while (item)
    {
      if (strcasecmp(item,nick) == 0)
        {
           stopped ++;
           item = irlist_delete(&(gdata.xlistqueue), item);
           continue;
         }
      item = irlist_get_next(item);
    }
  
  item = irlist_get_head(&(gdata.serverq_slow));
  while (item)
    {
      inick = NULL;
      copy = mystrdup(item);
      inick = strchr(copy, ' ');
      if (inick != NULL)
        {
          *(inick++) = 0;
          end = strchr(inick, ' ');
          if (end != NULL)
            {
              *(end++) = 0;
              if (strcasecmp(inick,nick) == 0)
                {
                   if ( (strcmp(copy,"PRIVMSG") == 0) || (strcmp(copy,"NOTICE") == 0) )
                     {
                       stopped ++;
                       mydelete(copy);
                       item = irlist_delete(&(gdata.serverq_slow), item);
                       continue;
                     }
                }
            }
        }
      mydelete(copy);
      item = irlist_get_next(item);
    }
  ioutput(CALLTYPE_MULTI_END,OUT_S|OUT_L|OUT_D,COLOR_YELLOW," (stopped %d)", stopped);
}

void notifyqueued_nick(const char *nick)
{
  int i;
  unsigned long rtime, lastrtime;
  pqueue *pq;
  transfer *tr;
  
  updatecontext();
  
  lastrtime=0;
  
  /* if we are sending more than allowed, we need to skip the difference */
  for (i=0; i<irlist_size(&gdata.trans)-gdata.slotsmax; i++)
    {
      rtime=-1;
      tr = irlist_get_head(&gdata.trans);
      while(tr)
        {
          int left = min2(359999,(tr->xpack->st_size-tr->bytessent)/((int)(max2(tr->lastspeed,0.001)*1024)));
          if (left > lastrtime && left < rtime)
            {
              rtime = left;
            }
          tr = irlist_get_next(tr);
        }
      if (rtime < 359999)
        {
          lastrtime=rtime;
        }
    }
  
  i=1;
  pq = irlist_get_head(&gdata.mainqueue);
  while(pq)
    {
      rtime=-1;
      tr = irlist_get_head(&gdata.trans);
      while(tr)
        {
          int left = min2(359999,(tr->xpack->st_size-tr->bytessent)/((int)(max2(tr->lastspeed,0.001)*1024)));
          if (left > lastrtime && left < rtime)
            {
              rtime = left;
            }
          tr = irlist_get_next(tr);
        }
      if (rtime < 359999)
        {
          lastrtime=rtime;
        }
      
      if (!strcasecmp(pq->nick, nick))
        {
          ioutput(CALLTYPE_NORMAL, OUT_S|OUT_D,COLOR_YELLOW,
                  "Notifying Queued status to %s",
                  nick);
          notice_slow(pq->nick,"Queued %lih%lim for \"%s\", in position %i of %i. %lih%lim or %s remaining.",
                  (long)(gdata.curtime-pq->queuedtime)/60/60,
                  (long)((gdata.curtime-pq->queuedtime)/60)%60,
                  pq->xpack->desc,
                  i,
                  irlist_size(&gdata.mainqueue),
                  lastrtime/60/60,
                  (lastrtime/60)%60,
                  (rtime >= 359999) ? "more" : "less");
        }
      i++;
      pq = irlist_get_next(pq);
    }
  
}

static int check_for_file_remove(int n)
{
  xdcc *xd;
  userinput *pubplist;
  char *tempstr;

  updatecontext();

  xd = irlist_get_nth(&gdata.xdccs, n-1);
  if (look_for_file_changes(xd) == 0)
    return 0;

  pubplist = mycalloc(sizeof(userinput));
  tempstr = mycalloc(maxtextlength);
  snprintf(tempstr,maxtextlength-1,"remove %d", n);
  u_fillwith_console(pubplist,tempstr);
  u_parseit(pubplist);
  mydelete(pubplist);
  mydelete(tempstr);
  return 1;
}

static int last_look_for_file_remove = -1;

void look_for_file_remove(void)
{
  int i;
  int p;
  int m;

  updatecontext();

  p = irlist_size(&gdata.xdccs);
  m = min2(20, p);
  for (i=0; i<m; i++) {
    last_look_for_file_remove ++;
    if (last_look_for_file_remove < 0 || last_look_for_file_remove >= p)
      last_look_for_file_remove = 0;

    if (check_for_file_remove(last_look_for_file_remove + 1))
      return;
  }
  return;
}

int has_joined_channels(int all)
{
  int j;
  int n;
  channel_t *ch;

  j=0;
  ch = irlist_get_head(&gdata.channels);
  while(ch)
    {
       if ((ch->flags & CHAN_ONCHAN) == 0)
         {
           if (all != 0)
             return 0;
         }
       else
         {
           j++;
           n++;
         }
       ch = irlist_get_next(ch);
     }
  return j;
}

void reset_download_limits(void)
{
  int num;
  int new;
  xdcc *xd;

  num = 0;
  xd = irlist_get_head(&gdata.xdccs);
  while(xd)
    {
      num++;
      if (xd->dlimit_max != 0)
        {
          new = xd->gets + xd->dlimit_max;
          ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR,
                  "Resetting download limit of pack %d, used %d",
                  num, new - xd->dlimit_used);
          xd->dlimit_used = new;
        }
      xd = irlist_get_next(xd);
    }
}

#ifdef USE_GEOIP

#define GEOIP_FLAGS GEOIP_MEMORY_CACHE

GeoIP *gi = NULL;

char *check_geoip(transfer *const t);
char *check_geoip(transfer *const t)
{
  static char hostname[20];
  static char code[20];
  const char *result;

  if (gi == NULL)
    {
      if (gdata.geoipdatabase != NULL)
        gi = GeoIP_open(gdata.geoipdatabase, GEOIP_FLAGS);
      else
        gi = GeoIP_new(GEOIP_FLAGS);
    }

  if (gi == NULL)
    {
      code[0] = 0;
      return code;
    }

  snprintf(hostname, sizeof(hostname), "%ld.%ld.%ld.%ld",
            t->remoteip>>24, (t->remoteip>>16) & 0xFF, (t->remoteip>>8) & 0xFF, t->remoteip & 0xFF );
  result = GeoIP_country_code_by_addr(gi, hostname);
  if (result == NULL)
    {
      code[0] = 0;
      return code;
    }

  code[0] = tolower(result[0]);
  code[1] = tolower(result[1]);
  code[2] = 0;
  return code;
}
#endif /* USE_GEOIP */

void check_new_connection(transfer *const tr)
{
#ifdef USE_GEOIP
  const char *country;
  char *msg;
#endif /* USE_GEOIP */
  
#ifdef USE_GEOIP
  country = check_geoip(tr);
  ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_YELLOW,
            "GeoIP [%s on %s]: Info %ld.%ld.%ld.%ld -> %s)",
            tr->nick,
            gdata.networks[ tr->net ].name,
            tr->remoteip>>24, (tr->remoteip>>16) & 0xFF,
            (tr->remoteip>>8) & 0xFF, tr->remoteip & 0xFF,
            country);
   
   if (irlist_size(&gdata.geoipcountry))
     {
       if (!verifyshell(&gdata.geoipcountry, country))
         {
           if (!verifyshell(&gdata.geoipexcludenick, tr->nick))
             {
               msg = mycalloc(maxtextlength);
               if (country == NULL)
                  country = "error";
               snprintf(msg, maxtextlength - 1, "Sorry, no downloads to your country = %s", country);
               t_closeconn(tr, msg, 0);
               ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR,
                        "IP from other country (%s) detected", country);
               mydelete(msg);
               return;
             }
         }
     }
#endif /* USE_GEOIP */
  
  if ((gdata.ignoreduplicateip) && (gdata.maxtransfersperperson > 0))
    {
      check_duplicateip(tr);
    }
}

void check_duplicateip(transfer *const newtr)
{
  igninfo *ignore;
  char *bhostmask;
  transfer *tr;
  int found;
  int num;

  num = 24 * 60; /* 1 day */
  found = 0;
  tr = irlist_get_head(&gdata.trans);
  while(tr)
    {
      if ((tr->tr_status == TRANSFER_STATUS_SENDING) &&
         (tr->remoteip == newtr->remoteip))
        {
          if (strcmp(tr->hostname,"man"))
            found ++;
        }
      tr = irlist_get_next(tr);
    }

  if (found <= gdata.maxtransfersperperson)
    return;

  tr = irlist_get_head(&gdata.trans);
  while(tr)
    {
      if ((tr->tr_status == TRANSFER_STATUS_SENDING) &&
         (tr->remoteip == newtr->remoteip))
        {
          if (strcmp(tr->hostname,"man"))
            {
              t_closeconn(tr, "You are being punished for pararell downloads", 0);
              bhostmask = mymalloc(strlen(tr->hostname)+5);
              sprintf(bhostmask, "*!*@%s", tr->hostname);
              ignore = irlist_get_head(&gdata.ignorelist);
              while(ignore)
                {
                  if (ignore->regexp && !regexec(ignore->regexp,bhostmask,0,NULL,0))
                    {
                      break;
                    }
                  ignore = irlist_get_next(ignore);
                }
              
              if (!ignore)
                {
                  char *tempstr;
                  
                  ignore = irlist_add(&gdata.ignorelist, sizeof(igninfo));
                  ignore->regexp = mycalloc(sizeof(regex_t));
                  
                  ignore->hostmask = mystrdup(bhostmask);
                  
                  tempstr = hostmasktoregex(bhostmask);
                  if (regcomp(ignore->regexp,tempstr,REG_ICASE|REG_NOSUB))
                    {
                      ignore->regexp = NULL;
                    }
                  
                  ignore->flags |= IGN_IGNORING;
                  ignore->lastcontact = gdata.curtime;
                  
                  mydelete(tempstr);
                }
              
              ignore->flags |= IGN_MANUAL;
              ignore->bucket = (num*60)/gdata.autoignore_threshold;
              
              ioutput(CALLTYPE_NORMAL,OUT_S|OUT_L|OUT_D,COLOR_NO_COLOR,
                      "same IP detected, Ignore activated for %s which will last %i min",
                      bhostmask,num);
              mydelete(bhostmask);
            }
        }
      tr = irlist_get_next(tr);
    }

  write_statefile();
}

char* getpart_eol(const char *line, int howmany)
{
  char *part;
  int li;
  size_t plen;
  int hi;
  
  li=0;
  
  for (hi = 1; hi < howmany; hi++)
    {
      while (line[li] != ' ')
        {
          if (line[li] == '\0')
            {
              return NULL;
            }
          else
            {
              li++;
            }
        }
      li++;
    }
  
  if (line[li] == '\0')
    {
      return NULL;
    }
  
  plen = strlen(line+li);
  part = mycalloc(plen+1);
  memcpy(part, line+li, plen);
  part[plen] = '\0';
  
  return part;
}

void identify_needed(int force)
{
  if (force == 0)
    {
      if ((gdata.next_identify > 0) && (gdata.next_identify >= gdata.curtime))
        return;
    }
  /* wait 1 sec before idetify again */
  gdata.next_identify = gdata.curtime + 1;
  privmsg("nickserv", "IDENTIFY %s", gdata.nickserv_pass);
  ioutput(CALLTYPE_NORMAL, OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR,
          "IDENTIFY send to nickserv.");
}

void identify_check(const char *line)
{
  if (strstr(line, "Nickname is registered to someone else") != NULL)
    {
      identify_needed(0);
    }
  if (strstr(line, "This nickname has been registered") != NULL)
    {
      identify_needed(0);
    }
  if (strstr(line, "This nickname is registered and protected") != NULL)
    {
      identify_needed(0);
    }
  if (strstr(line, "please choose a different nick") != NULL)
    {
      identify_needed(0);
    }
}

/* End of File */


syntax highlighted by Code2HTML, v. 0.9.1