#include "bbs.h"

int dsendstatustodaemon(sessionrecordtyp sessionrecords[],
                        confrecordtyp *confrecord, const int sockd)
{
  int n, status;
  PID_T pid, spid;
  
  if (recvn(sockd,(void *)&pid,(SIZE_T)sizeof(PID_T),0)<0 ||
      recvn(sockd,(void *)&status,(SIZE_T)sizeof(int),0)<0 ) {
    bgerror("dsendstatustodaemon","recv: %m");
    return(-1);
  }
  n = -1;
  do {
    n++;
    spid = sessionrecords[n].pid;
  } while (pid!=spid && spid!=0);
  if (spid == 0) {
    bgerror("dsendstatustodaemon","cannot found user %ld",(long)pid);
    return(-1);
  }
  sessionrecords[n].status = status;
  return(0);
}


int diniconnecttouser(sessionrecordtyp sessionrecords[],
                      confrecordtyp *confrecord, const int sockd)
  /*
  Socket fuer talk einrichten
  Returnwerte: 1, wenn Partner besetzt
               0, wenn Partner frei
	      <0 bei Fehler
  */
{
  PID_T inipid, recpid, pid;
  int n;
  boolean inifound, recfound;
  char path[TALKSOCKNAMELEN+1];

  if (recvn(sockd,(void *)&inipid,(SIZE_T)sizeof(PID_T),0)<0 ||
      recvn(sockd,(void *)&recpid,(SIZE_T)sizeof(PID_T),0)<0 ) {
    bgerror("diniconnecttouser","recv: %m");
    return(-1);
  }

  n = 0;
  inifound = FALSE;
  recfound = FALSE;
  do {
    pid = sessionrecords[n].pid;
    if (pid == inipid) {
      sessionrecords[n].talking_to = recpid;
      inifound = TRUE;
    }
    else if (pid == recpid) {
      if (sessionrecords[n].talking_to > 0) {
	return(1);
      }
      sessionrecords[n].talking_to = inipid;
      recfound = TRUE;
    }
    n++;
  } while (!(inifound && recfound) && pid!=0);
  if (pid == 0) {
    bgerror("diniconnecttouser","cannot found both parties");
    return(-1);
  }
  n = 0;
  sendn(sockd,(void *)&n,(SIZE_T)sizeof(int),0);
  sprintf(path,"talk-%ld-%ld",(long)inipid,(long)recpid);
  sendn(sockd,(void *)path,(SIZE_T)TALKSOCKNAMELEN,0);
  
  return(0);
}


int dabortconnecttouser(sessionrecordtyp sessionrecords[],
                        confrecordtyp *confrecord, const int sockd)
{
  PID_T inipid, recpid, pid;
  int n;
  boolean inifound, recfound;

  if (recvn(sockd,(void *)&inipid,(SIZE_T)sizeof(PID_T),0)<0 ||
      recvn(sockd,(void *)&recpid,(SIZE_T)sizeof(PID_T),0)<0 ) {
    bgerror("dabortconnecttouser","recv: %m");
    return(-1);
  }
  n = 0;
  inifound = FALSE;
  recfound = FALSE;
  do {
    pid = sessionrecords[n].pid;
    if (pid == inipid) {
      sessionrecords[n].talking_to = 0;
      inifound = TRUE;
    }
    else if (pid == recpid) {
      sessionrecords[n].talking_to = 0;
      recfound = TRUE;
    }
    n++;
  } while (!(inifound && recfound) && pid!=0);
  if (pid == 0) {
    bgerror("dabortconnecttouser","cannot found both parties %ld and %ld",
            (long)inipid,(long)recpid);
    return(-1);
  }  
  return(0);
}



int dremconnecttouser(sessionrecordtyp sessionrecords[],
                      confrecordtyp *confrecord, const int sockd)
  /*
  Returnwerte: 1, wenn Partner besetzt
               0, wenn Partner frei
	      <0 bei Fehler
  */
{
  PID_T rempid;
  int n, snr;
  boolean inifound;
  char path[TALKSOCKNAMELEN+1];

  if (recvn(sockd,(void *)&rempid,(SIZE_T)sizeof(PID_T),0) < 0) {
    bgerror("dremconnecttouser","recv: %m");
    return(-1);
  }

  snr = 0;
  inifound = FALSE;
  while (sessionrecords[snr].pid!=0 && !inifound) {
    if (rempid == sessionrecords[snr].talking_to) {
      inifound = TRUE;
    }
    else {
      snr++;
    }    
  }
  if (! inifound) {
    bgerror("dremconnecttouser","cannot found caller %ld",(long)rempid);
    return(-1);
  }
  n = 0;
  sendn(sockd,(void *)&n,(SIZE_T)sizeof(int),0);
  sprintf(path,"talk-%ld-%ld",(long)sessionrecords[snr].pid,(long)rempid);
  sendn(sockd,(void *)path,(SIZE_T)TALKSOCKNAMELEN,0);
  sendn(sockd,(void *)&(sessionrecords[snr]),(SIZE_T)sizeof(sessionrecordtyp),0);
  
  return(0);
}


int dputinlog(const int logfilefd, const int sockd)
  /*
  Logtext vom Client empfangen und in Logfile schreiben
  */
{
  SIZE_T nleft, nanz, n;
  SSIZE_T nread;
  char buf[BUFSIZE];
  
  if (recvn(sockd,(void *)&n,(SIZE_T)sizeof(SIZE_T),0)<0) {
    bgerror("dputinlog","recv: %m");
    return(-1);
  }
  nleft = n;
  while (nleft > 0) {
    nanz = nleft > BUFSIZE ? BUFSIZE : nleft;
    if ((nread=recvn(sockd,(void *)buf,nanz,0)) < 0) {
      return(-1);
    }
    if ((nread=writen(logfilefd,(void *)buf,(SIZE_T)nread)) < 0) {
      return(-1);
    }
    nleft -= (SIZE_T)nread;
  }
  return (int)n;
}


int dgetsessions(sessionrecordtyp sessionrecords[], const int sockd)
  /*
  Clients auf Existenz pruefen und sessionrecords senden
  */
{
  int k, n;
  
  n = rmdeadsessions(sessionrecords);
  for (k=0; k<n; k++) {
    sendn(sockd,(void *)&(sessionrecords[k]),(SIZE_T)sizeof(sessionrecordtyp),0);
  }
  sendn(sockd,(void *)&(sessionrecords[n]),(SIZE_T)sizeof(sessionrecordtyp),0);
  return n;
}


int daddsession(sessionrecordtyp sessionrecords[], const int sockd)
  /*
  sessionrecord vom Client empfangen und in sessionrecords speichern
  */
{
  int k=0;
  sessionrecordtyp sr;

  if (recvn(sockd,(void *)&sr,(SIZE_T)sizeof(sessionrecordtyp),0) !=
          (SSIZE_T)sizeof(sessionrecordtyp)) {
    bgerror("daddsession","recv: %m");
    return -1;
  }
  while (sessionrecords[k].pid!=0) {
    k++;
  }
  cpysr(&(sessionrecords[k]), &sr);
  sessionrecords[k].talking_to = 0;
  sessionrecords[++k].pid = 0;
  return 0;
}


int dremovesession(sessionrecordtyp sessionrecords[], const int sockd)
  /*
  Pid vom Client empfangen und zugehoerige session entfernen
  */
{
  PID_T pid;
  int k=0;
  
  if (recvn(sockd,(void *)&pid,(SIZE_T)sizeof(PID_T),0) !=
          (SSIZE_T)sizeof(PID_T)) {
    bgerror("dremovesession","recv: %m");
    return -1;
  }
  while (sessionrecords[k].pid!=pid && sessionrecords[k].pid!=0) {
    k++;
  }
  while (sessionrecords[k].pid!=0) {
    cpysr(&(sessionrecords[k]), &(sessionrecords[k+1]));
    k++;
  }
  return 0;
}


int dgetuserrecord(const int sockd, confrecordtyp *confrecord)
  /*
  Usernamen vom Client empfangen, dazugehoerigen Record aus dem Userfile
  lesen und an den Client senden.
  Wird kein passender Userrecord gefunden, so wird 1 zuruckgegeben und
  userrecord.user==NOUSER
  */
{
  int g=1, znr=1, z=2;
  char zeile[PATH_MAX+S_STRLEN+1], username[S_STRLEN+1], *key, *arg;
  userrecordtyp userrecord;
  FILE *fd;
  
  /* Defaultwerte */
  strcpy(userrecord.name,NOUSER);
  strcpy(userrecord.passwd,NOPASSWORD);
  userrecord.loglevel = DEFLOGLEVEL;
  userrecord.seclevel = HIGHSECURITY;
  userrecord.kermitok = DEFKERMITOK;
  userrecord.protokoll = ZMODEMPROTO;
  userrecord.autozmodem = DEFAUTOZMODEM;
  userrecord.fullist_on_cd = DEFFULLIST;
  strcpy(userrecord.home,DEFHOME);
  strcpy(userrecord.uploaddir,DEFUPLOADDIR);
  strcpy(userrecord.shell,NOSHELL);
  strcpy(userrecord.path,NOPATH);
  strcpy(userrecord.term,DEFTERM);
  userrecord.lines = DEFLINES;
  userrecord.columns = DEFCOLUMNS;
  userrecord.lang = DEFLANGUAGE;

  if (recvn(sockd,(void *)username,(SIZE_T)S_STRLEN,0)<0) {
    bgerror("dgetuserrecord","recv: %m");
    return -1;
  }
  
  if ((fd=fopen(confrecord->usersfile,"r"))==NULL) {
    bgerror("dgetuserrecord","fopen %s: %m",confrecord->usersfile);
    return -1;
  }
  do {
    z = fgetnln(zeile,PATH_MAX+S_STRLEN,fd);
    znr++;
    if (z>=PATH_MAX+S_STRLEN) {
      bgerror("dgetuserrecord","line %i too long",znr);
      fclose(fd);
      return -1;
    }
    if (z>0 && zeile[0]!='#') {
      if ((g=strcmp(zeile,username))!=0) {
	do {
	  z = fgetnln(zeile,PATH_MAX,fd);
	  znr++;
	} while (z>=0 && z<PATH_MAX && zeile[0]!='$');
      }
    }
  } while (z>=0 && z<PATH_MAX && g!=0);
    
  if (g==0) {
    strcpy(userrecord.name,username);
    do {
      z = fgetnln(zeile,PATH_MAX,fd);
      znr++;
      if (z<0 && z>=PATH_MAX) {
	bgerror("dgetuserrecord","error in userfile %s, line %i",
		confrecord->usersfile, znr);
	fclose(fd);
	return -1;
      }
      split2key_arg(zeile,&key,&arg);
      if (*key=='\0' || *key=='#') {
	/* */
      }
      else if (strncmp("pass",key,4)==0) {
	strcpy(userrecord.passwd,arg);
      }
      else if (strncmp("loglevel",key,4)==0) {
	userrecord.loglevel = atoi(arg);
      }
      else if (strncmp("seclevel",key,4)==0) {
	userrecord.seclevel = atoi(arg);
      }
      else if (strncmp("kermitok",key,4)==0) {
	userrecord.kermitok = atoi(arg);
      }
      else if (strncmp("protokoll",key,4)==0) {
	userrecord.protokoll = atoi(arg);
      }
      else if (strncmp("autozmodem",key,5)==0) {
	userrecord.autozmodem = atoi(arg);
      }
      else if (strncmp("fullist_on_cd",key,8)==0) {
        userrecord.fullist_on_cd = atoi(arg);
      }
      else if (strncmp("home",key,4)==0) {
	strcpy(userrecord.home,arg);
      }
      else if (strncmp("upload",key,4)==0) {
	strcpy(userrecord.uploaddir,arg);
      }
      else if (strncmp("shell",key,4)==0) {
	strcpy(userrecord.shell,arg);
      }
      else if (strncmp("path",key,4)==0) {
	strcpy(userrecord.path,arg);
      }
      else if (strncmp("term",key,4)==0) {
	strcpy(userrecord.term,arg);
      }
      else if (strncmp("lines",key,4)==0) {
	userrecord.lines = atoi(arg);
      }
      else if (strncmp("columns",key,4)==0) {
	userrecord.columns = atoi(arg);
      }
      else if (strncmp("lang",key,4)==0) {
	userrecord.lang = atoi(arg);
      }
    } while (zeile[0] != '$');
    z = 0;
  }
  else {
    z = 1;
  }
  fclose(fd);
  sendn(sockd,(char *)&userrecord,sizeof(userrecordtyp),0);
  return z;
}


int dsaveuserrecord(const int sockd, confrecordtyp *confrecord)
  /*
  Empfaengt vom Client einen Userrecord und speichert ihn im Userfile ab
  */
{
  int k;
  char zeile[PATH_MAX+S_STRLEN+1], tempfile[PATH_MAX+1], *username;
  userrecordtyp userrecord;
  FILE *infd, *outfd;
  
  if (recvn(sockd,(char *)&userrecord,sizeof(userrecordtyp),0)<0) {
    bgerror("dsaveuserrecord","recvn: %m");
    return -1;
  }
  
  if ((infd=fopen(confrecord->usersfile,"r"))==NULL) {
    bgerror("dsaveuserrecord","fopen %s: %m",confrecord->usersfile);
    return -1;
  }
  sprintf(tempfile,"%s-%ld",confrecord->usersfile,(long)getpid());
  if ((outfd=fopen(tempfile,"w"))==NULL) {
    bgerror("dsaveuserrecord","fopen %s: %m",tempfile);
    fclose(infd);
    return -1;
  }
  
  username = userrecord.name;
  if (fgetnln(zeile,PATH_MAX+S_STRLEN,infd)<0) {
    fclose(infd);
    return -1;
  }
  while (strcmp(zeile,username)!=0) {  
    if (fprintf(outfd,"%s\n",zeile)<0) {
      bgerror("dsaveuserrecord","fprintf: %m");
      fclose(infd);
      return -1;
    }
    if(fgetnln(zeile,PATH_MAX+S_STRLEN,infd)<0) {
      fclose(infd);
      return -1;
    }
  }
  fprintf(outfd,"%s\n",username);
  fprintf(outfd,"Password: %s\n",userrecord.passwd);
  fprintf(outfd,"Loglevel: %d\n",userrecord.loglevel);
  fprintf(outfd,"Seclevel: %d\n",userrecord.seclevel);
  fprintf(outfd,"Kermitok: %d\n",userrecord.kermitok);
  fprintf(outfd,"Protokoll: %d\n",userrecord.protokoll);
  fprintf(outfd,"Autozmodem: %d\n",userrecord.autozmodem);
  fprintf(outfd,"Fullist_on_cd: %d\n",userrecord.fullist_on_cd);
  fprintf(outfd,"Home: %s\n",userrecord.home);
  fprintf(outfd,"Uploaddir: %s\n",userrecord.uploaddir);
  fprintf(outfd,"Shell: %s\n",userrecord.shell);
  fprintf(outfd,"Path: %s\n",userrecord.path);
  fprintf(outfd,"Term: %s\n",userrecord.term);
  fprintf(outfd,"Lines: %d\n",userrecord.lines);
  fprintf(outfd,"Columns: %d\n",userrecord.columns);
  fprintf(outfd,"Lang: %d\n",userrecord.lang);
  do {
    if(fgetnln(zeile,PATH_MAX+S_STRLEN,infd)<0) {
      fclose(infd);
      return -1;
    }
  } while(zeile[0]!='$');
  if (fprintf(outfd,"$\n")<0) {
    bgerror("dsaveuserrecord","fprintf: %m");
    fclose(infd);
    return -1;
  }
  while ((k=fgetnln(zeile,PATH_MAX+S_STRLEN,infd))>=0) {
    if (fprintf(outfd,"%s\n",zeile)<0) {
      bgerror("dsaveuserrecord","fprintf: %m");
      fclose(infd);
      return -1;
    }
  }
  fclose(infd);
  k = -1;
  if (fclose(outfd)>=0) {
    if (unlink(confrecord->usersfile)==0) {
      k = rename(tempfile,confrecord->usersfile);
    }
  }
  return k;
}
