#include <stdio.h>
#include <string.h>

#include "bastypes.h"
#include "os.h"
#include "num2nam.h"
#include "util.h"
#include "wsock.h"
#include "news.h"
#include "cfg_file.h"

/* ------------------------------------------------------------------------ */

int connections = 0;
tU32 starttimer;

void message ( unsigned long typ, unsigned long num, char *msg, news_callst *call )
{
  OSRequestMutexSem(&call->sema_handle2,-1);
    call->message_callback (typ,num,msg,call);
  OSReleaseMutexSem(&call->sema_handle2);
}

tU32 send_command (char* cmd, int isock)
{
  char loccmd[2048];
  int  i;
  int  s;

  strcpy (loccmd,cmd);
  strcat (loccmd,"\r\n");

  for (i=0;i<(int)strlen(loccmd);i++) {
    do {
      Sleep(1);
      s = wsock_send(isock, &loccmd[i], 1);
      if (s == SOCKET_ERROR) return (0);
    } while (s!=1);
  }
  return (1);
}

int read_headline( news_callst *call,int isock)
{
  char c[2];
  int  len=1;
  char serverreply[2048];

//  Sleep(1000);
  strcpy (serverreply,"");
  c[0]=0;
  c[1]=0;

  while (c[0] != 10) {
    len = wsock_recv(  isock, &c[0], 1);
    if (len <= 0) return(0);
    strcat (serverreply,c);
  }
  serverreply[strlen(serverreply)-1] = 0;
  serverreply[strlen(serverreply)-1] = 0;
  message ( 2,0,serverreply,call );
  return (1);
}

int news_get_list_exex (news_callst *call)
{
  int  len;
  int  isock;
  int  i;
  unsigned int  u;
  char readbuff[16384];
  char linestr [16384];
  char help_list[2048];
  char help_use [2048];
  char help     [2048];
  char helpstr1 [2048];
  char helpstr2 [2048];
  int  linectr;
  int  counter=0;
  FILE *listfile;
  FILE *usefile;

  strcpy (linestr,"");
  linectr=0;
  strcpy (help_list,call->newsserver_name);strcat (help_list,"\\");strcat (help_list,call->groupfile_name_list);
  strcpy (help_use ,call->newsserver_name);strcat (help_use ,"\\");strcat (help_use ,call->groupfile_name_use );


  isock = wsock_attach(call->newsserver_name,call->port_number);
  if (!isock) return (0);

  connections++;

  OsMkDir(call->newsserver_name);
  if (!read_headline(call, isock)) return (0);

  listfile = fopen (help_list,"wb");
  if (!listfile) return (0);

  if (!send_command("LIST",isock)) return (0);

  while (strcmp(".",linestr)) {
    len = wsock_recv(  isock, (char *)&readbuff, sizeof(readbuff));
    if (len <= 0) return (0);
    for (i=0;i<len;i++) {
      if (readbuff[i] != 13) {
        if (readbuff[i] == 10) {
          linestr[linectr] = 0;
          linectr = 0;
          for (u=0;u<strlen(linestr);u++) if (linestr[u] == ' ') linestr[u] = 0;
          if ((strcmp(".",linestr)) && (strlen(linestr) > 7)) {
            counter++;
            printf ("%i %s                                 \r",counter,linestr);
            fprintf(listfile,"%s\r\n",linestr);
          }
        } else {
          linestr[linectr++] = readbuff[i];
        }
      }
    }
  }
  fclose (listfile); listfile = 0;
  printf ("Number of Newsgroups found on %s: %i\r\n",call->newsserver_name,counter);
  sprintf (help,"\r\nNumber of Newsgroups (%s)found: %i\r\n",call->newsserver_name,counter);
  message (2,counter,help,call);
  wsock_detach(isock);

//if (!util_file_exist(help_use)) util_copy_file (help_list,help_use);
  if (!util_file_exist(help_use)) {
    listfile = fopen (help_list,"r");
    if (listfile) {
      usefile = fopen (help_use,"w");
      if (usefile) {
        while (fgets(helpstr1,sizeof(helpstr1),listfile)) {
          strcpy (helpstr2,"#");
          strcat (helpstr2,helpstr1);
          fputs (helpstr2,usefile);
        }
        fclose (usefile); usefile=0;
      }
      fclose (listfile);listfile=0;
    }
  }
  return (1);
}

int news_get_list_ex (news_callst *call)
{
  int rc;

  call->threadcounter++;
    rc = news_get_list_exex (call);
  call->threadcounter--;
  return (rc);
}

int news_get_list (news_callst *call)
{
  _beginthread (news_get_list_ex,0,call);
  Sleep(1000); // give time to increment threadcounters
  return (1);
}

int set_lastread(news_callst *call,char *group,long num)
{
  FILE *l;
  char help[2048];

  strcpy (help,call->newsserver_name);
  strcat (help,"\\");
  strcat (help,group);
  strcat (help,"\\");
  strcat (help,call->lastread_name);

  l=fopen (help,"w");
  if (!l) return (0);

  sprintf (help,"%d",num);
  fputs (help,l);
  fclose (l);l=0;

  return (1);
}

long get_lastread(news_callst *call,char * group)
{
  FILE *l;
  char help[2048];

  strcpy (help,call->newsserver_name);
  strcat (help,"\\");
  strcat (help,group);
  strcat (help,"\\");
  strcat (help,call->lastread_name);

  l=fopen (help,"r");
  if (!l) return (0);

  fgets (help,200,l);
  fclose (l);l=0;
  return (strtol(help,NULL,10));
}

int get_news_number (news_callst *call,char *group,long number, int isock)
{
  char cmd [2048];
  char num [2048];
  char name[2048];
  char linestr[16384];
  char readbuff[16384];
  int  len;
  int linectr;
  char c='x';
  int i;
  FILE *fn;

  strcpy  (name,call->newsserver_name);
  strcat  (name,"\\");
  strcat  (name,group);
  strcat  (name,"\\");
  sprintf (num,"news%06d.txt",number);
  strcat  (name,num);
  fn = fopen (name,"wb");

  if (!fn) return (0);


    strcpy (cmd,"STAT ");
    sprintf (num,"%i",number);
    strcat (cmd,num);
    if (!send_command (cmd,isock)) return(0);
    c = 0;
    while (c!=10) {
      len=wsock_recv(isock, (char *)&c,1);
      if (len<=0) return(0);
    };
    if (!call->noheadflag) {
      if (!send_command ("HEAD",isock)) return(0);
      c = 0;
      while (c!=10){
        len=wsock_recv(isock, (char *)&c,1);
        if (len<=0) return(0);
      };


      linestr[0]=0;
      linectr=0;

      while (strcmp(".",linestr)) {
        len = wsock_recv(  isock, (char *)&readbuff, sizeof(readbuff));
        if (len <= 0) return (0);
          for (i=0;i<len;i++) {
            if (readbuff[i] != 13) {
              if (readbuff[i] == 10) {
                linestr[linectr] = 0;
                linectr = 0;
                if (strcmp(".",linestr)) {
                  fprintf(fn,"%s\r\n",linestr);
                }
              } else {
                linestr[linectr++] = readbuff[i];
              }
            }
          }
      }

      fprintf(fn,"\r\n");
    }

    if (!call->nobodyflag) {
      if (!send_command ("BODY",isock)) return (0);
      c = 0;
      while (c!=10) {
        len=wsock_recv(isock, (char *)&c,1);
        if (len <= 0) return (0);
      }


      linestr[0]=0;
      linectr=0;

      while (strcmp(".",linestr)) {
        len = wsock_recv(  isock, (char *)&readbuff, sizeof(readbuff));
        if (len <= 0) return (0);
          for (i=0;i<len;i++) {
            if (readbuff[i] != 13) {
              if (readbuff[i] == 10) {
                linestr[linectr] = 0;
                linectr = 0;
                if (strcmp(".",linestr)) {
                  fprintf(fn,"%s\r\n",linestr);
                }
              } else {
                linestr[linectr++] = readbuff[i];
              }
            }
          }
      }
    }
    fclose (fn);fn=0;
  return (1);
}

int get_news (news_callst *call,char *group,long lastr,int isock)
{
  char msg[2048];
  char cmdstr[2048];
  int  len;
  char readbuff[16384];
  long i;
  long from;
  long to;
  long nextread;
  unsigned long secs;

  nextread = lastr+1; //next to read;

  strcpy (cmdstr,"GROUP ");
  strcat (cmdstr,group);

  if (!send_command (cmdstr,isock)) return (0);
//  Sleep (500);
  len = wsock_recv(  isock, (char *)&readbuff   , sizeof(readbuff));

  if (len <= 0) return (0);
    readbuff[len-2] = 0;
    from = strtol(strtok( readbuff, " "),NULL,10);
    from = strtol(strtok( NULL    , " "),NULL,10);
    from = strtol(strtok( NULL    , " "),NULL,10);
    to   = strtol(strtok( NULL    , " "),NULL,10);

    if (from > nextread) nextread = from;
    i = nextread;

    if (!call->nostatflag) {
      if (to > nextread) {
        for (i=nextread;i<=to;i++) {
          if (!get_news_number (call,group,i,isock)) return (0);
            secs = (OsGetTickCount()-starttimer) / 1000;
            sprintf (msg,"%d/%d/%d-Processing: %s (%d/%d), read:%d, left:%d (%d/%d)",call->threadcounter,connections,call->gcnt,group,from,to,i-nextread,to-i,wsock_send_bytes()/secs,wsock_recv_bytes ()/secs);
            message (3,call->threadcounter,msg,call);
            if (!(i%100)) set_lastread(call,group,i);
        }
      }
    }
  set_lastread(call,group,to);
  return (1);
}


int get_next_group (news_callst *call,char *group)
{
  char help[2048];

  if (call->group_file_handle) {
    if (fgets(group,200,call->group_file_handle)) {
      group[strlen(group)-1] = 0;
      if (strlen(group)) {
        call->gcnt++;
        sprintf (help,"groupcounter=%i",call->gcnt);
        message (4,call->gcnt,help,call);
        return (1);
      }
    } else {
      fclose (call->group_file_handle); call->group_file_handle = 0;
      strcpy (group,"");
      return (0);
    }
  }
  strcpy (group,"");
  return (0);
}

int get_news_from_list (news_callst *call)
{
  int isock;
  char group[2048];
  char help[2048];
  int  rc;

  isock = wsock_attach(call->newsserver_name,call->port_number);
  if (!isock) return(0);
  connections++;
  if (!read_headline(call,isock)) return(0);
  strcpy (group,"-");
  while (strlen(group)) {
    OSRequestMutexSem(&call->sema_handle1,-1);
      rc = get_next_group(call,group);
    OSReleaseMutexSem(&call->sema_handle1);
    if (!rc) return (0);
    if (strlen(group) && (group[0] != '#')) {
      strcpy (help,call->newsserver_name);
      strcat (help,"\\");
      strcat (help,group);
      OsMkDir(help);
      strcat (help,"\\");
      strcat (help,call->lastread_name);
      if (!util_file_exist(help)) set_lastread(call,group,0);
      if (!get_news (call,group,get_lastread(call,group),isock)) {
        return (0);
        break;
      }
    }
  }
  wsock_detach(isock);
  return (1);
}

int pre_get_news_from_list (news_callst *call)
{
  int rc;
  call->threadcounter++;
    rc = get_news_from_list (call);
  call->threadcounter--;
  return (rc);
}

int news_get_news (news_callst* call)
{
  int    i;
  char   help [2048];

  OsMkDir(call->newsserver_name);

  strcpy (help,call->newsserver_name); strcat (help,"\\"); strcat (help,call->groupfile_name_use );

  if (!util_file_exist(help)) return (0);

  call->group_file_handle = fopen  (help,"r");
  if (!call->group_file_handle) return (0);

  for (i=1;i<=call->max_threads;i++) {
    _beginthread (pre_get_news_from_list,0,call);
    Sleep(1000); // give time to increment threadcounters
  }
  return (1);
}

int news_get_error_number (news_callst *call)
{
  return (call->rc);
}

char *news_get_error_str(news_callst *call)
{
  return (call->error_str);
}

int news_init (news_callst *call)
{
  memset (call,0,sizeof(news_callst));

  config_file_read_string (CFG_FILE_NAME, GROUPFILE_LIST_TOK, call->groupfile_name_list, GROUPFILE_LIST_DEF);
  config_file_read_string (CFG_FILE_NAME, GROUPFILE_USE_TOK , call->groupfile_name_use , GROUPFILE_USE_DEF );
  config_file_read_string (CFG_FILE_NAME, LASTREAD_TOK      , call->lastread_name      , LASTREAD_DEF      );

  strcpy (call->error_str,"No Error");
  call->rc = 0;

  OSCreateMutexSem("\\sem32\\ctsem1",&call->sema_handle1,0,FALSE);
  OSCreateMutexSem("\\sem32\\ctsem1",&call->sema_handle2,0,FALSE);

  starttimer = OsGetTickCount();

  return (1);
}
int news_exit (news_callst *call)
{
  OSCloseMutexSem(&call->sema_handle2);
  OSCloseMutexSem(&call->sema_handle1);
  return (1);
}
int news_ready (news_callst *call)
{
  if (call->threadcounter) return (0); else return (1);
}



