ftp.nice.ch/pub/next/unix/communication/ft_bbs.1.0.s.tar.gz#/ft_bbs-1.0/menue.c

This is menue.c in view mode; [Download] [Up]

/* $Id: menue.c,v 1.2 1995/12/19 19:30:47 eilts Exp eilts $ */
#include "bbs.h"


int getcmdline_c(char cmdline[], const menuetyp startmenue[],
         const menuetyp sysmenue[], const menuetyp bbsmenue[],
	 const chrootrecordtyp *chrootrecord, confrecordtyp *confrecord)
{
  int arganz, lang;
  static boolean insysmenue = FALSE;
  static boolean inbbsmenue = FALSE;
  static boolean inreader = FALSE;
  char key;
  static char nextkey=NO_KEY;
  SIGSET_T sigset;
  
  sendstatustodaemon(BBS_IDLE,confrecord);
  setsighandler(SIGUSR1, sigtalkaccepthandler);
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGUSR1);
  sigprocmask(SIG_UNBLOCK,&sigset,NULL);
  lang = confrecord->userrecord.lang;
  noecho();
  crmode();
  arganz = -1;
  cmdline[0] = '\0';
  if (insysmenue) {
    key = SYS_KEY;
  }
  else if (inbbsmenue) {
    key = BBS_KEY;
  }
  else {
    key = selectmenue_c(cmdline, startmenue, msg("getcmdline_c",0,lang), 
                        nextkey, "", confrecord);
  }
  sigaddset(&sigset, SIGUSR2);
  sigprocmask(SIG_BLOCK,&sigset,NULL);
  sendstatustodaemon(BBS_BUSY,confrecord);
  nextkey = NO_KEY;
  switch (key) {
  case HELP_KEY:
    arganz = 0;
    break;
  case DOC_KEY:
    arganz = 0;
    break;
  case SYS_KEY:
    insysmenue = TRUE;
    key = selectmenue_c(cmdline, sysmenue, msg("getcmdline_c",1,lang), 
                        NO_KEY, "", confrecord);
    switch (key) {
    case ENV_KEY:
      arganz = 0;
      break;
    case LANG_KEY:
      arganz = sprache_c(cmdline, confrecord);
      break;
    case PROT_KEY:
      arganz = protokoll_c(cmdline, confrecord);
      break;
    case AUTOZ_KEY:
      arganz = autozmodem_c(cmdline, confrecord);
      break;
    case FULLIST_KEY:
      arganz = fullist_c(cmdline, confrecord);
      break;
    case TERM_KEY:
      arganz = term_c(cmdline, confrecord);
      break;
    case PASSWD_KEY:
      arganz = newpasswd_c(cmdline, confrecord);
      break;
    case QUIT_KEY:
    case ESCAPE_KEY:
      insysmenue = FALSE;
      break;
    }
    break;
  case DIR_KEY:
    arganz = 0;
    break;
  case CD_KEY:
    arganz = selectdir_c(cmdline, chrootrecord, "cd", confrecord);
    if (arganz >= 0) {      
      nextkey = CD_KEY;
    }
    else {
      writetouser(confrecord,msg("getcmdline_c",3,lang),chrootrecord->cwdname);
    }
    break;
  case PWD_KEY:
    arganz = 0;
    break;
  case SHOW_KEY:
    arganz = selectfiles_c(cmdline, 0, "show", confrecord);
    if (arganz < 1) cmdline[0] = '\0';
    break;
  case DOWNLOAD_KEY:
    arganz = selectfiles_c(cmdline, MAXARGS, "get", confrecord);
    if (arganz < 1) cmdline[0] = '\0';
    break;
  case UPLOAD_KEY:
    arganz = put_c(cmdline, confrecord);
    break;
  case AUTOZDETECTED:
    arganz = 0;
    break;
  case BBS_KEY:
    inbbsmenue = TRUE;
    key = selectmenue_c(cmdline, bbsmenue, msg("getcmdline_c",2,lang),
			inreader?MSGBROWSE_KEY:NO_KEY, "", confrecord);
    switch (key) {
    case TALK_KEY:
      arganz = talk_c(cmdline, confrecord);
      break;
    case SYSOPMAIL_KEY:
      arganz = sendmail_c(cmdline, NULL, NULL, NULL, TRUE, chrootrecord,
                          confrecord);
      if (arganz < 2) cmdline[0] = '\0';
      break;
    case EMAIL_KEY:
      arganz = sendmail_c(cmdline, NULL, NULL, NULL, FALSE, chrootrecord,
                          confrecord);
      if (arganz < 2) cmdline[0] = '\0';
      break;
    case MESSAGE_KEY:
      arganz = sendmessage_c(cmdline, NULL, NULL, NULL, chrootrecord,
                             confrecord);
      if (arganz < 2) cmdline[0] = '\0';
      break;
    case MSGBROWSE_KEY:
      inreader = TRUE;
      arganz = msgbrowser_c(cmdline, bbsmenue, chrootrecord, confrecord);
      if (arganz < 1) {
        inreader = FALSE;
        cmdline[0] = '\0';
      }
      break;
#ifdef NNTPNEWS
    case NEWSBROWSE_KEY:
      arganz = newsbrowser_c(confrecord);
      cmdline[0] = '\0';
      break;
    case NEWSPOST_KEY:
      arganz = postarticle_c(NULL, NULL, NULL, NULL, NULL, confrecord);
      cmdline[0] = '\0';
      break;
    case NEWSSUBSCR_KEY:
      arganz = subscribenewsgroups_c(confrecord);
      cmdline[0] = '\0';
      break;
#endif
    case QUIT_KEY:
    case ESCAPE_KEY:
      inbbsmenue = FALSE;
      break;
    }
    break;
  case QUIT_KEY:
    arganz = bbsquit_c(cmdline, confrecord);
    break;
  default:
    cmdline[0] = '\0';
  }
  return arganz;
}


char selectmenue_c(char cmd[], const menuetyp menue[], const char *kopfstr,
                   const char nextkey, const char *helpcontext,
                   const confrecordtyp *confrecord)
{
  int lang, z, k;
  char c, key, cset[100];
  
  if (nextkey == NO_KEY) {
    lang = confrecord->userrecord.lang;
    for (k=0, z=0; (c=menue[k].key)!='\0'; k++) {
      if (*(menue[k].dec) != '\0') cset[z++] = c;
    }
    cset[z] = '\0';
    clear();
    move(0, (COLS - strlen(kopfstr)) / 2);
    addstr(kopfstr);
    for (k=0,z=2; (c=menue[k].key)!='\0'; k++,z++) {
      if (c == ' ') continue;
      move(z,10);
      addch('[');
      standout();
      addch(c);
      standend();
      addch(']');
      move(z,16);
      addstr(menue[k].dec[lang]);
    }
    key = getkeyonprompt(msg("selectmenue_c",0,lang), cset, TRUE, TRUE,
                         helpcontext, confrecord);
  }
  else {
    key = nextkey;
  }
  if (key == ESCAPE_KEY) return key;
  if (key == AUTOZDETECTED) {
    c = UPLOAD_KEY;
  }
  else {
    c = key;
  }
  k = 0;
  while (menue[k].key!='\0') {
    if (menue[k].key==c && *(menue[k].dec)!='\0') break;
    k++;
  }
  strcpy(cmd,menue[k].cmd);
  return key;
}


#ifdef NNTPNEWS
int newsbrowser_c(const confrecordtyp *confrecord)
{
  int lang, newsrc_anz, k, n;
  char key, *bgbuf, *sp, str[STRLEN+1];
  boolean sync_newsrc;
  newsstattyp newsrecord;
  grouptyp grouprecord;
  tlistetyp *newsrcliste = (tlistetyp *)0;
  tlistetyp *artliste = (tlistetyp *)0;
  
  lang = confrecord->userrecord.lang;
  bbslog(LOG_FILE,confrecord,"newsbrowser_c");
  if (checknewsperms(confrecord) < 0) {
    writetouser(confrecord,msg("newsbrowser_c",0,lang));
    errormsg(E_LOGFILE,confrecord,"bbs","newsbrowser_c",
             "no permittion to read news");
    return 0;
  }

  if (createnewsrcdb(&newsrecord,confrecord) == NULL) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","newsbrowser_c",
             "cannot create newsrc DB");
    return -1;
  }
  
  newsrc_anz = newsrcdbtolist(&newsrcliste,newsrecord.newsrcdb,confrecord);
  sortliste(newsrcliste,TL_BLOCKLEN,newsrc_anz,confrecord);
  bgbuf = showmsgline(msg("newsbrowser_c",1,lang),confrecord->nntpserver);
  if (nntp_connect(&newsrecord,confrecord) < 0) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","newsbrowser_c",
	     "cannot connect to Newsserver %s:",confrecord->nntpserver,
	     newsrecord.lastretstr);
    removeliste(&newsrcliste,TRUE,TL_BLOCKLEN);
    newsrecord.newsrcdb->close(newsrecord.newsrcdb);
    return -1;
  }

  *grouprecord.groupname = '\0';
  while (TRUE) {
    sprintf(str,msg("newsbrowser_c",2,lang),newsrc_anz);
    key = selectpager_c(newsrcliste,newsrc_anz,str,NULL,TRUE,
                        "newsbrowser_grpselect",confrecord);
    if (key == ESCAPE_KEY)  break;
    for (k=0; k<newsrc_anz; k++) {
      readliste(&newsrcliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
      if (*sp == 'T')  break;
    }
    if (newsrc_anz == 0 || *sp != 'T') {
      sp = str;
      *str = 'F';
      if (getnewsgrpname(&str[1],confrecord) == 1) {
        *str = 'T';
/*
        key = getkeyonprompt(msg("newsbrowser_c",3,lang),"AU",TRUE,FALSE,
	                     NULL,confrecord);
        if (key == 'A')  unread_only = FALSE;
*/
      }
    }
    if (*sp == 'T') {
      *sp = '!';
      strcpy(grouprecord.groupname,&sp[1]);
      browsegroup(&grouprecord,&newsrecord,confrecord);
      n = lookupnewsrcdb(newsrecord.newsrcdb,grouprecord.groupname,0,NULL,0,
			  confrecord);
      if (n > 0) {
	key = getkeyonprompt(msg("newsbrowser_c",4,lang),"JYN",TRUE,FALSE,
			      "newsbrowser_subscribe",confrecord);
      }
      if (n == 0 || (n > 0 && key != 'N')) {
	sync_newsrc = (confrecord->userrecord.seclevel != HIGHSECURITY);
	updatenewsrc(newsrecord.newsrcdb,&grouprecord,sync_newsrc,confrecord);
	if (n > 0 && key != 'N') {
	  strcpy(str,"!");
	  strmaxcat(str,grouprecord.groupname,STRLEN);
	  addstrtoliste(&newsrcliste,TRUE,newsrc_anz++,TL_BLOCKLEN,str,
	                confrecord);
	}
      }
      removeliste(&artliste,TRUE,TL_BLOCKLEN);
    }
  }
  showmsgline("quit newsserver %s ...",confrecord->nntpserver);
  nntp_close(&newsrecord);
  removeliste(&newsrcliste,TRUE,TL_BLOCKLEN);
  newsrecord.newsrcdb->close(newsrecord.newsrcdb);
  return 0;
}


int postarticle_c(const char *file, const char *groups, const char *subj,
                  const char *refs, newsstattyp *newsrec,
		  const confrecordtyp *confrecord)
{
  int anz, n, k, lang;
  char newsgroups[ARG_MAX+1], nstr[ARG_MAX+1], letter[PATH_MAX+1],
       str[2*STRLEN+2], subject[STRLEN+1], *splits[MAXARGS+1],
       *sp, *bgbuf, key = '\0';
  tlistetyp *tliste = (tlistetyp *)0;
 
  lang = confrecord->userrecord.lang;
  move(0,0);
  clear();
  standout();
  addstr(msg("postarticle_c",0,lang));
  standend();
  if (checknewsperms(confrecord) < 1) {
    writetouser(confrecord,msg("postarticle_c",1,lang));
    errormsg(E_LOGFILE,confrecord,"bbs","postarticle_c",
             "no permittion to post");
    return 0;
  }
  move(2,0);
  addstr(msg("postarticle_c",7,lang));
  do {
    *newsgroups = '\0';
    if (groups != NULL) {
      strmaxcpy(newsgroups,groups,ARG_MAX);
      anz = splitstring(splits,newsgroups,',',MAXARGS);
      for (n=0; n < anz; n++) {
        *str = 'T';
        strcpy(&str[1],splits[n]);
        addstrtoliste(&tliste,TRUE,n,TL_BLOCKLEN,str,confrecord);
      }
      key = selectpager_c(tliste,anz,msg("postarticle_c",0,lang),NULL,FALSE,
                          NULL,confrecord);
      *newsgroups = '\0';
      if (key != ESCAPE_KEY) {
        for (n=0; n < anz; n++) {
          readliste(&tliste,FALSE,n,TL_BLOCKLEN,&sp,confrecord);
          if (*sp == 'T') {
            strmaxcat(newsgroups,&sp[1],ARG_MAX-1);
            strcat(newsgroups,",");
        }
        }
        newsgroups[strlen(newsgroups)-1] = '\0';
      }
      removeliste(&tliste,TRUE,TL_BLOCKLEN);
      move(2,0);
      clrtobot();
    }
    n = 0;
    if (key != ESCAPE_KEY) {
      move(8,0);
      clrtobot();
      addstr(msg("postarticle_c",2,lang));
      n = readfromuser(newsgroups,newsgroups,ARG_MAX,TRUE,confrecord);
    }
    if (n <= 0)  return n;
    strmaxcpy(nstr,newsgroups,ARG_MAX);
    anz = splitstring(splits,nstr,',',MAXARGS);
    for (n=0,k=0; n < anz; n++) {
      if (checkgroup(splits[n],confrecord) == 0) {
        k++;
        errormsg(E_LOGFILE|E_USER,confrecord,"bbs","postarticle_c",
                 msg("postarticle_c",3,lang),splits[n]);
      }
    }
    if (k > 0) {
      key = getkeyonprompt(msg("postarticle_c",4,lang),"PRAWN",TRUE,
                           FALSE,NULL,confrecord);
    }
    else {
      key = 'P';
    }
    if (key == 'A')  return 0;
  } while (key != 'P' && key != 'W');

  move(10,0);
  addstr(msg("postarticle_c",5,lang));
  if (readfromuser(subject,subj,STRLEN,TRUE,confrecord) == 0) {
    return 0;
  }
  if (file == NULL) {
    scratchfilename(letter,"post-",NULL,confrecord->scratchdir);
  }
  else {
    strcpy(letter,file);
  }
  n = edit(letter,0600,FALSE,0,confrecord);
  if (n == 0) {
    bgbuf = showmsgline(msg("postarticle_c",6,lang));
    if (*confrecord->nntppost == 'Y' || *confrecord->nntppost == 'y') {
      n = do_postart_nntp(newsgroups,subject,refs,letter,newsrec,confrecord);
    }
    else {
      n = do_postart_inews(newsgroups,subject,refs,letter,confrecord);
    }
  }
  else if  (n > 0) {
    unlink(letter);
    return 0;
  }
  return n;
}


int subscribenewsgroups_c(const confrecordtyp *confrecord)
{
  int k, n, anz, lang;
  char key, str[2*STRLEN+3], *sp, *bgbuf;
  boolean oldgroup, err = FALSE;
  DBASE_DB *newsrcdb;
  DBASE_DBT dbkey, dbdata;
  newsstattyp newsrecord;
  tlistetyp *tliste = (tlistetyp *)0;

  lang = confrecord->userrecord.lang;
  move(0,0);
  clear();
  standout();
  addstr(msg("subscribenewsgroups_c",0,lang));
  standend();
  if (checknewsperms(confrecord) < 0 ||
      confrecord->userrecord.seclevel == HIGHSECURITY) {
    writetouser(confrecord,msg("subscribenewsgroups_c",1,lang));
    errormsg(E_LOGFILE,confrecord,"bbs","subscribenewsgroups_c",
             "no permittion to subscribe news");
    return 0;
  }

  if (createnewsrcdb(&newsrecord,confrecord) == NULL) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","subscribenewsgroups_c",
             "cannot create newsrc DB");
    return -1;
  }
  newsrcdb = newsrecord.newsrcdb;
  bgbuf = showmsgline(msg("subscribenewsgroups_c",2,lang));
  if ((anz=getallnewsgroups(&tliste,GROUPNAME_MASK,confrecord)) < 0) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","subscribenewsgroups_c",
	      "cannot get list of all newsgroups");
    newsrcdb->close(newsrcdb);
    return -1;
  }
/*
  removemsgline(bgbuf);
*/
  sortliste(tliste,TL_BLOCKLEN,anz,confrecord);
  for (k=0; k<anz; k++) {
    readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
    if (lookupnewsrcdb(newsrcdb,sp,0,NULL,0,confrecord) == 0) {
      *str = 'T';
    }
    else {
      *str = 'F';
    }
    strcpy(&str[1],sp);
    addstrtoliste(&tliste,TRUE,k,TL_BLOCKLEN,str,confrecord);
  }
  key =
selectpager_c(tliste,anz,msg("subscribenewsgroups_c",0,lang),
              NULL,FALSE,"subscribenewsgroups",confrecord);
  if (selectpagerquit_c(key) > 0) {
    for (k=0; k<anz; k++) {
      readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
      oldgroup = (lookupnewsrcdb(newsrcdb,&sp[1],0,NULL,0,confrecord) == 0);
      if (*sp == 'F' && oldgroup) {
	DBASE_SIZE(dbkey) = strlen(&sp[1]) + 1;
	DBASE_DATA(dbkey) = &sp[1];
	n = newsrcdb->del(newsrcdb,&dbkey,0);
	if (n > 0) {
	  errormsg(E_LOGFILE|E_USER,confrecord,"bbs","subscribenewsgroups_c",
		    "no entry %s in newsrc DB",&sp[1]);
	}
	else if (n < 0) {
	  errormsg(E_LOGFILE|E_USER,confrecord,"bbs","subscribenewsgroups_c",
		    "cannot delete newsrc DB entry %s: %m",&sp[1]);
	  err = TRUE;
	}
      }
      else if (*sp == 'T' && ! oldgroup) {
	DBASE_SIZE(dbkey) = strlen(&sp[1]) + 1;
	DBASE_DATA(dbkey) = &sp[1];
	DBASE_SIZE(dbdata) = 1;
	DBASE_DATA(dbdata) = "";
	n = newsrcdb->put(newsrcdb,&dbkey,&dbdata,R_NOOVERWRITE);
	if (n > 0) {
	  errormsg(E_LOGFILE|E_USER,confrecord,"bbs","subscribenewsgroups_c",
		    "duplicaty key %s in newsrc DB", &sp[1]);
	}
	else if (n < 0) {
	  errormsg(E_LOGFILE|E_USER,confrecord,"bbs","subscribenewsgroups_c",
		    "cannot add key %s to newsrc DB: %m",&sp[1]);
	  err = TRUE;
	}
      }
    }
    removeliste(&tliste,TRUE,TL_BLOCKLEN);
    if (err) {
      newsrcdb->close(newsrcdb);
      return -1;
    }
    anz = newsrcdbtolist(&tliste,newsrcdb,confrecord);
    if (anz < 0 || syncnewsrcdb(newsrcdb,confrecord) < 0) {
      anz = -1;
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","subscribenewsgroups_c",
		"saving newsrc failed");
    }
    removeliste(&tliste,TRUE,TL_BLOCKLEN);
  }
  newsrcdb->close(newsrcdb);
  return anz;
}


char newspager_c(tlistetyp *tliste, const int anz, const char *header,
                 const char *subheader, const boolean hotselect,
                 const char *helpcontext, const confrecordtyp *confrecord)
{
  int kopfzeilen, lines, zstep, offset, ypos, kmax, k, n;
  char *zary[MAXMEN], key;

  clear();
  move(0,0);
  standout();
  addstr(header);
  standend();
  if (subheader != (char *)0) {
    kopfzeilen = 3;
    move(1,0);
    addstr(subheader);
  }
  else {
    kopfzeilen = 2;
  }
  lines = confrecord->userrecord.lines - kopfzeilen -1;
  if (lines > MAXMEN) lines = MAXMEN;
  zstep = lines - 2;
  offset = 0;
  do {
    move(kopfzeilen,0);
    clrtobot();
    kmax = offset+lines > anz ? anz : offset+lines;
    for (k=offset,n=0; k<kmax; k++,n++) {
      ypos = kopfzeilen + k - offset;
      readliste(&tliste,FALSE,k,TL_BLOCKLEN,&(zary[n]),confrecord);
      if (*zary[n]!='X') {
	move(ypos,2);
	addch('[');
	standout();
	addch('A'+k-offset);
	standend();
	addch(']');
      }
      move(ypos,6);
      addstr_withmargin(&(zary[n][1]));
    }
    if (anz > lines) {
      if (offset+lines < anz) {
        n = offset +1;
      }
      else {
        n = 0;
      }
    }
    else {
      n = -1;      
    }
    key = menueselect_c(zary,kmax-offset,n,kopfzeilen,hotselect,helpcontext,
                        confrecord);
    if (key == ALLQUANTOR_KEY) {
      newsdateselect_c(tliste,anz,confrecord);
    }
    if (pagerstep(key) < 0) {
      offset -= zstep;
    }
    else if (pagerstep(key) > 0) {
      offset += zstep;
    }
    if (offset > anz-lines) offset = anz-lines;
    if (offset < 0) offset = 0;
  } while (selectpagerquit_c(key) == 0);
  
  return key;
}


int newsdateselect_c(tlistetyp *tliste, const int anz,
                     const confrecordtyp *confrecord)
{
  int fromtime, totime, isttime, year, k, n, lang;
  char str[S_STRLEN+1], sstr[S_STRLEN+1], *sp, *splits[5], c;

  lang = confrecord->userrecord.lang;
  move(LINES-1,0);
  clrtoeol();
  standout();
  addstr(msg("newsdateselect_c",0,lang));
  standend();
  refresh();
  c = bbsgetch(TRUE);
  if (c == '?') {
    writetouser(confrecord,msg("newsdateselect_c",1,lang));
    refresh();
    c = bbsgetch(TRUE);
  }
  if (c == ESCAPE_KEY || c == RETURN_KEY || c == NEWLINE_KEY) {
    return(0);
  }
  else {
    str[0] = c;
    str[1] = '\0';
    if (readfromuser(str,str,S_STRLEN,TRUE,confrecord) == 0)  return 0;
  }
  for (k=0; str[k] && str[k]!='-' && k<S_STRLEN; k++)  sstr[k] = str[k];
  sstr[k] = '\0';
  n = splitstring(splits,sstr,'.',4);
  if (n == 2) {
    sp = gettime();
    year = atoi(&sp[20]);
  }
  else if (n == 3) {
    year = atoi(splits[2]);
    if (year > 90 && year < 1900) {
      year += 1900;
    }
    else if (year < 2000) {
      year += 2000;
    }
  }
  else {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","newsdateselect_c",
             msg("newsdateselect_c",2,lang));
    return -1;
  }
  fromtime = atoi(splits[0]) + 31 * (atoi(splits[1]) + 12 * year);
  if ((sp=strchr(str,'-')) != NULL) {
    sp++;
    strcpy(sstr,sp);
    n = splitstring(splits,sstr,'.',4);
    if (n == 2) {
      /* */
    }
    else if (n == 3) {
      year = atoi(splits[2]);
      if (year > 90 && year < 1900) {
        year += 1900;
      }
      else if (year < 2000) {
        year += 2000;
      }
    }
    else {
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","newsdateselect_c",
               msg("newsdateselect_c",2,lang));
      return -1;
    }
    totime = atoi(splits[0]) + 31 * (atoi(splits[1]) + 12 * year);
  }
  else {
    totime = 0;
  }

  for (k=0; k < anz; k++) {
    readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
    isttime = getdatenum(splittoken(sp,'\n',3));
    if (isttime < 0) {
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","newsdateselect_c",
               "%s: unknown month",splits[1]);
      continue;
    }
    if (isttime >= fromtime && (totime == 0 || isttime <= totime)) {
      *sp = (*sp == 'T') ? 'F' : 'T';
    }
  }
  return 0;
}
#endif


int msgbrowser_c(char cmd[], const menuetyp bbsmenue[],
                 const chrootrecordtyp *chrootrecord,
                 const confrecordtyp *confrecord)
{
  int lang, n, k, nr, anz;
  char *sp, *splits[MAXARGS+1], key, zeile[2*STRLEN+6], addr[STRLEN+1],
       realname[STRLEN+1];
  boolean corrupthdr = FALSE;
  static boolean firstcall = TRUE;
  tlistetyp *tliste = (tlistetyp *)0, *idliste = (tlistetyp *)0;

  lang = confrecord->userrecord.lang;
  anz = listmessages(&tliste,confrecord);
  if (anz == 0) {
    if (firstcall)  writetouser(confrecord,msg("msgbrowser_c",0,lang));
    firstcall = FALSE;
    return 0;
  }
  for (k=0; k<anz; k++) {
    readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
    if (splitstring(splits,sp,'\n',3) != 3) {
      corrupthdr = TRUE;
      addstrtoliste(&tliste,TRUE,k,TL_BLOCKLEN,"Xcorrupt entry (not readable)",
                    confrecord);
      addstrtoliste(&idliste,TRUE,k,TL_BLOCKLEN,"",confrecord);      
    }
    else {
      switch (addresstyp(splits[0],confrecord)) {
      case 0:
        key = 'M';
        break;
      case 1:
        key = 'S';
        break;
      case 2:
        key = 'L';
        break;
      case 3:
        key = 'R';
        break;
      default:
        key = '?';
      }
      parseaddrline(addr,realname,splits[0]);
      sp = *realname != '\0' ? realname : addr;
      sprintf(zeile,"F%s (%c): %s",sp,key,splits[1]);
      addstrtoliste(&tliste,TRUE,k,TL_BLOCKLEN,zeile,confrecord);
      addstrtoliste(&idliste,TRUE,k,TL_BLOCKLEN,splits[2],confrecord);
    }
  }
  if (corrupthdr && firstcall) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","msgbrowser_c",
             "some headers are corrupted");
  }
  
  key = selectpager_c(tliste,anz,msg("msgbrowser_c",1,lang),NULL,TRUE,
                      "msgbrowser_select",confrecord);
  n = 0;
  if (key != ESCAPE_KEY) {
    for (nr=0; nr<anz; nr++) {
      readliste(&tliste,FALSE,nr,TL_BLOCKLEN,&sp,confrecord);
      if (*sp == 'T') {
        key = getkeyonprompt(msg("msgbrowser_c",2,lang),"RDAG",TRUE,FALSE,
	                     "msgbrowser_menu",confrecord);
        readliste(&idliste,FALSE,nr,TL_BLOCKLEN,&sp,confrecord);
        if (key == 'A') {
          n = mailreply(cmd,nr,sp,bbsmenue,chrootrecord,confrecord);
	}
	else {
	  strcpy(zeile,cmd);
	  sprintf(cmd,"%s -a %c -n %d -i %s",zeile,key,nr,sp);
	  n = 2;
	}
	break;
      }
    }
  }
  removeliste(&tliste,TRUE,TL_BLOCKLEN);
  removeliste(&idliste,TRUE,TL_BLOCKLEN);
  
  return n;
}


int sendmessage_c(char cmd[], const char *file, const char *addr,
                  const char *subj, const chrootrecordtyp *chrootrecord,
                  const confrecordtyp *confrecord)
{
  int n, k, anz, lang;
  char *sp, key, str[STRLEN+1], str2[STRLEN+1],
       letter[PATH_MAX+1], address[ARG_MAX+1], subject[STRLEN+1],
       user_l[STRLEN+1], *splits[MAXARGS+1];
  tlistetyp *tliste;
  
  lang = confrecord->userrecord.lang;
  if (*(confrecord->userrecord.realname)) {
    sprintf(user_l,"%s <%s>",confrecord->userrecord.realname,
            confrecord->userrecord.name);
  }
  else {
    strcpy(user_l,confrecord->userrecord.name);
  }
  tliste = (tlistetyp *)0;
  if ((anz=getallusernames(&tliste,USERNAME_MASK|REALNAME_MASK,
      confrecord)) < 0) {
    return -1;
  }
#ifdef NO_MESSAGES_TO_YOURSELF
  for (k=0; k<anz; k++) {
    readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
    if (strcmp(sp,user_l) == 0) {
      delfromliste(&tliste,TRUE,k,&anz,TL_BLOCKLEN,confrecord);
      break;
    }
  }
#endif
  sortliste(tliste,TL_BLOCKLEN,anz,confrecord);
  if (addr != NULL) {
    strmaxcpy(address,addr,ARG_MAX);
    splitstring(splits,address,',',MAXARGS);
    for (n=0; splits[n] != NULL; n++) {
      parseaddrline(str,str2,splits[n]);
      strcpy(splits[n],str);
    }
  }
  for (k=0; k<anz; k++) {
    readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
    *str = 'F';
    if (addr != NULL) {
      for (n=0; splits[n] != NULL; n++) {
        parseaddrline(str,str2,sp);
        if (strcmp(splits[n],str) == 0) {
          *str = 'T';
	  break;
	}
      }
    }
    strcpy(&str[1],sp);
    addstrtoliste(&tliste,TRUE,k,TL_BLOCKLEN,str,confrecord);
  }
  key = selectpager_c(tliste,anz,msg("sendmessage_c",0,lang),NULL,FALSE,
		      "sendmessage",confrecord);
  n = 0;
  *address = '\0';
  if (key != ESCAPE_KEY) {
    for (k=0; k<anz; k++) {
      readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
      if (*sp == 'T') {
	strmaxcat(address,&sp[1],ARG_MAX-1);
	strcat(address,",");
	n++;
      }
    }
  }
  removeliste(&tliste,TRUE,TL_BLOCKLEN);
  
  if (n > 0) {
    address[strlen(address)-1] = '\0';
    clear();
    move(2,0);
    addstr(msg("sendmessage_c",0,lang));
    addch(' ');
    addstr(address);
    addstr(msg("sendmessage_c",1,lang));
    if (readfromuser(subject,subj,STRLEN,TRUE,confrecord) == 0) {
      return 0;
    }
    if (file == NULL) {
      scratchfilename(letter,"letter-",NULL,confrecord->scratchdir);
      unlink(letter);
    }
    else {
      strcpy(letter,file);
    }
    if (edit(letter,0600,FALSE,0,confrecord) == 0) {
      strmaxcat(cmd," -l ",ARG_MAX);
      strmaxcat(cmd,getchrootpath(letter,confrecord->scratchdir),ARG_MAX);
      n = 2;
      if (*subject != '\0') {
        strmaxcat(cmd," -s ",ARG_MAX);
        strmaxcat(cmd,subject,ARG_MAX);
        n = 3;
      }
      strmaxcat(cmd," -a ",ARG_MAX);
      strmaxcat(cmd,address,ARG_MAX);
      if (strlen(cmd) >= ARG_MAX) {
        errormsg(E_LOGFILE|E_USER,confrecord,"bbs","sendmessage_c",
                 "line too long");
        return -1;
      }
      return n;
    }
    else {
      unlink(letter);
      n = 0;
    }
  }
  return n;
}


int sendmail_c(char cmd[], const char *file, const char *addr,
               const char *subj, const boolean sysopmail,
               const chrootrecordtyp *chrootrecord,
               const confrecordtyp *confrecord)
{
  int anz, lang, n;
  char path[PATH_MAX+1], letter[PATH_MAX+1], address[ARG_MAX+1],
       str[2*STRLEN+2], subject[STRLEN+1], *splits[MAXARGS+1], *sp, key = '\0';
  tlistetyp *tliste = (tlistetyp *)0;
  
  lang = confrecord->userrecord.lang;
  move(0,0);
  clear();
  standout();
  addstr(msg("sendmail_c",0,lang));
  standend();
  addstr(msg("sendmail_c",4,lang));
  addstr(msg("sendmail_c",1,lang));
  if (sysopmail) {
    printw("%s (Sysop)",confrecord->sysop);
    strmaxcpy(address,confrecord->sysop,STRLEN);
    n = 1;
  }
  else {
    *address = '\0';
    if (addr != NULL) {
      strmaxcpy(address,addr,ARG_MAX);
      anz = splitstring(splits,address,',',MAXARGS);
      for (n=0; n < anz; n++) {
	*str = 'T';
	strcpy(&str[1],splits[n]);
	addstrtoliste(&tliste,TRUE,n,TL_BLOCKLEN,str,confrecord);
      }
      key = selectpager_c(tliste,anz,msg("sendmail_c",0,lang),NULL,FALSE,
			  NULL,confrecord);
      *address = '\0';
      if (key != ESCAPE_KEY) {
	for (n=0; n < anz; n++) {
	  readliste(&tliste,FALSE,n,TL_BLOCKLEN,&sp,confrecord);
	  if (*sp == 'T') {
	    strmaxcat(address,&sp[1],ARG_MAX-1);
	    strcat(address,",");
	  }
	}
	address[strlen(address)-1] = '\0';
      }
      removeliste(&tliste,TRUE,TL_BLOCKLEN);
      move(1,0);
      clrtobot();
      move(2,0);
    }
    n = 0;
    if (key != ESCAPE_KEY) {
      n = readfromuser(address,address,ARG_MAX,TRUE,confrecord);
    }
    if (n > 0) {
      if ((n=checkmailperms(address,confrecord)) != 0) {
        writetouser(confrecord,msg("sendmail_c",3,lang));
        errormsg(E_LOGFILE,confrecord,"bbs","sendmail_c",
                 "address %s: no permittion (typ %d)",address,n);
        return 0;
      }
      n = 1;
    }
  }
  if (n > 0) {
    addstr(msg("sendmail_c",2,lang));
    if (readfromuser(subject,subj,STRLEN,TRUE,confrecord) == 0) {
      return 0;
    }
    strcpy(path,confrecord->scratchdir);
    if (file == NULL) {
      sprintf(letter,"%s/letter.%ld",path,(long)getpid());
    }
    else {
      strcpy(letter,file);
    }
    if (edit(letter,0600,FALSE,0,confrecord) == 0) {
      strmaxcat(cmd," -l ",ARG_MAX);
      if (chrootrecord != NULL) {
        strmaxcat(cmd,getchrootpath(letter,confrecord->scratchdir),ARG_MAX);
      }
      else {
        strmaxcat(cmd,letter,ARG_MAX);
      }
      strmaxcat(cmd," -a ",ARG_MAX);
      strmaxcat(cmd,address,ARG_MAX);
      n = 2;
      if (*subject != '\0') {
        strmaxcat(cmd," -s ",ARG_MAX);
        strmaxcat(cmd,subject,ARG_MAX);
	n++;
      }
      if (strlen(cmd) >= ARG_MAX) {
        errormsg(E_LOGFILE|E_USER,confrecord,"bbs","sendmail_c",
	         "line too long");
	return -1;
      }
      return n;
    }
    else {
      unlink(letter);
    }
  }
  return 0;
}


int talk_c(char cmd[], const confrecordtyp *confrecord)
{
  int k, n, nr, anz, lang;
  PID_T mypid;
  char key, str[2*S_STRLEN+1], *params[10], *sp;
  const char *mp;
  sessionrecordtyp sessionrecords[MAXSESSIONS];
  tlistetyp *tliste;

  lang = confrecord->userrecord.lang;
  mypid = getpid();
  if ((anz=getsessions(sessionrecords,MAXSESSIONS,confrecord)) < 0) {
    return(-1);
  }
  tliste = (tlistetyp *)0;
/*
  addstrtoliste(&tliste,TRUE,0,TL_BLOCKLEN,"",confrecord);
*/
  n = 0;
  for (nr=0; nr<anz; nr++) {
    if (sessionrecords[nr].pid != mypid) {
      if (sessionrecords[nr].talking_to > 0) {
        mp = msg("talk_c",0,lang);
      }
      else if (sessionrecords[nr].status == BBS_BUSY) {
        mp= msg("talk_c",1,lang);
      }
      else {
        mp= msg("talk_c",2,lang);
      }
      sprintf(str,"F%s   (TTY %s, PID %ld) %s",sessionrecords[nr].user,
              sessionrecords[nr].tty,(long)sessionrecords[nr].pid,mp);
      addstrtoliste(&tliste,TRUE,n++,TL_BLOCKLEN,str,confrecord);
    }
  }
  anz = n;

  if (anz > 0) {
    sortliste(tliste,TL_BLOCKLEN,anz,confrecord);
    key = selectpager_c(tliste,anz,msg("talk_c",3,confrecord->userrecord.lang),
                        NULL,TRUE,"talk",confrecord);
    n = 0;
    if (key != ESCAPE_KEY) {
      for (k=0; k<anz; k++) {
	readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
	if (*sp == 'T') {
	  splitparams(params,sp);
	  strcat(cmd," ");
	  strcat(cmd,params[4]);
	  cmd[strlen(cmd)-1] = '\0';
	  n++;
	}
      }
    }
  }
  else {
    writetouser(confrecord,msg("talk_c",4,confrecord->userrecord.lang));
    n = 0;
  }
  removeliste(&tliste,TRUE,TL_BLOCKLEN);
  
  return n;
}


int newpasswd_c(char cmd[], const confrecordtyp *confrecord)
{
  int lang, k=0;
  char str[PASS_MAX+S_STRLEN+10], username[S_STRLEN+1], newpasswd[PASS_MAX+1];

  lang = confrecord->userrecord.lang;
  move(k,0);
  clear();
  standout();
  printw(msg("newpasswd_c",0,lang),PASS_MAX);
  standend();
  k += 2;
  move(k,0);
  printw(msg("newpasswd_c",6,lang));
  refresh();
  k += 2;
  move(k,0);
  if (confrecord->userrecord.seclevel == HIGHSECURITY) {
    writetouser(confrecord,msg("newpasswd_c",1,lang));
    cmd[0] = '\0';
    return(0);
  }
  if (strcmp(confrecord->userrecord.name,confrecord->sysop) == 0) {
    k += 2;
    move(k,0);
    addstr(msg("newpasswd_c",2,lang));
    readfromuser(username,confrecord->userrecord.name,S_STRLEN,TRUE,
                 confrecord);
  }
  else {
    strcpy(username,confrecord->userrecord.name);
  }
  if (*username=='\0' || strchr(username,ESCAPE_KEY)!=NULL) {
    cmd[0] = '\0';
    return(0);
  }    
  k += 2;
  move(k,0);
  addstr(msg("newpasswd_c",3,lang));
  readfromuser(str,NULL,PASS_MAX,FALSE,confrecord);
  if (*str=='\0' || strchr(str,ESCAPE_KEY)!=NULL) {
    cmd[0] = '\0';
    return(0);
  }
  strcpy(newpasswd,str);
  k++;
  move(k,0);
  addstr(msg("newpasswd_c",4,lang));
  readfromuser(str,NULL,PASS_MAX,FALSE,confrecord);
  if (strncmp(newpasswd,str,PASS_MAX) != 0) {
    writetouser(confrecord,msg("newpasswd_c",5,lang));
    cmd[0] = '\0';
    return(0);
  }    
  
  strcpy(str,cmd);
  sprintf(cmd,"%s %s %s",str,username,newpasswd);
  
  return(2);
}


int sprache_c(char cmd[], const confrecordtyp *confrecord)
{
  int lang, ypos, k;
  char key;
  char cset[] = {'A','B','Q','\0'};
  
  lang = confrecord->userrecord.lang;
  move(0,0);
  clear();
  standout();
  addstr(msg("sprache_c",0,lang));
  standend();
  move(2,2);
  addstr(msg("sprache_c",1,lang));
  addstr(sprachennamen[confrecord->userrecord.lang]);
  for (k=0; k<2; k++) {
    ypos = k + 5;
    move(ypos,2);
    addch('[');
    standout();
    addch('A'+k);
    standend();
    addch(']');
    move(ypos,6);
    addstr(sprachennamen[k]);
  }
  ypos = k + 6;
  move(ypos,2);
  addch('[');
  standout();
  addch('Q');
  standend();
  addch(']');
  move(ypos,6);
  addstr(msg("sprache_c",2,lang));
  key = getkeyonprompt(msg("sprache_c",3,lang), cset, TRUE, FALSE, "lang",
                       confrecord);
  if (key==ESCAPE_KEY || key=='Q')  return(0);
  k = 1;
  if (key == 'A') {
    strcat(cmd," d");
  }
  else if (key == 'B') {
    strcat(cmd," e");
  }
  else {
    k = 0;
  }
  return(k);
}


int autozmodem_c(char cmd[], const confrecordtyp *confrecord)
{
  int lang, ypos, k;
  char key;
  char cset[] = {'A','Q','\0'};
  
  lang = confrecord->userrecord.lang;
  move(0,0);
  clear();
  standout();
  addstr(msg("autozmodem_c",0,lang));
  standend();
  move(2,2);
  if (confrecord->userrecord.autozmodem) {
    addstr(msg("autozmodem_c",1,lang));
  }
  else {
    addstr(msg("autozmodem_c",2,lang));
  }
  ypos = 4;
  move(ypos,2);
  addch('[');
  standout();
  addch('A');
  standend();
  addch(']');
  move(ypos,6);
  addstr(msg("autozmodem_c",3,lang));
  ypos += 2;
  move(ypos,2);
  addch('[');
  standout();
  addch('Q');
  standend();
  addch(']');
  move(ypos,6);
  addstr(msg("autozmodem_c",4,lang));
  key = getkeyonprompt(msg("autozmodem_c",5,lang), cset, TRUE, FALSE,
                       "autoz", confrecord);
  if (key==ESCAPE_KEY || key=='Q')  return(0);
  k = 1;
  if (key == 'A') {
    if (confrecord->userrecord.autozmodem) {
      strcat(cmd," n");
    }
    else {
      strcat(cmd," j");
    }
  }
  else {
    k = 0;
  }
  return(k);
}


int fullist_c(char cmd[], const confrecordtyp *confrecord)
{
  int lang, ypos, k;
  char key;
  char cset[] = {'A','Q','\0'};
  
  lang = confrecord->userrecord.lang;
  move(0,0);
  clear();
  standout();
  addstr(msg("fullist_c",0,lang));
  standend();
  move(2,2);
  if (confrecord->userrecord.fullist_on_cd) {
    addstr(msg("fullist_c",1,lang));
  }
  else {
    addstr(msg("fullist_c",2,lang));
  }
  ypos = 4;
  move(ypos,2);
  addch('[');
  standout();
  addch('A');
  standend();
  addch(']');
  move(ypos,6);
  addstr(msg("fullist_c",3,lang));
  ypos += 2;
  move(ypos,2);
  addch('[');
  standout();
  addch('Q');
  standend();
  addch(']');
  move(ypos,6);
  addstr(msg("fullist_c",4,lang));
  key = getkeyonprompt(msg("fullist_c",5,lang), cset, TRUE, FALSE, "dironcd",
                       confrecord);
  if (key==ESCAPE_KEY || key=='Q')  return(0);
  k = 1;
  if (key == 'A') {
    if (confrecord->userrecord.fullist_on_cd) {
      strcat(cmd," n");
    }
    else {
      strcat(cmd," j");
    }
  }
  else {
    k = 0;
  }
  return(k);
}


int put_c(char cmd[], const confrecordtyp *confrecord)
{
  if (confrecord->userrecord.protokoll == ZMODEMPROTO &&
      confrecord->userrecord.autozmodem) {
    writetouser(confrecord,msg("put_c",0,confrecord->userrecord.lang));
    cmd[0] = '\0';
  }
  return(0);
}


int protokoll_c(char cmd[], const confrecordtyp *confrecord)
{
  int lang, ypos, k;
  char key;
  char cset[] = {'A','B','Q','\0'};
  
  lang = confrecord->userrecord.lang;
  move(0,0);
  clear();
  standout();
  addstr(msg("protokoll_c",0,lang));
  standend();
  move(2,2);
  addstr(msg("protokoll_c",1,lang));
  addstr(protokollnamen[confrecord->userrecord.protokoll]);
  for (k=0; k<2; k++) {
    ypos = k + 5;
    move(ypos,2);
    addch('[');
    standout();
    addch('A'+k);
    standend();
    addch(']');
    move(ypos,6);
    addstr(protokollnamen[k]);
  }
  ypos = k + 6;
  move(ypos,2);
  addch('[');
  standout();
  addch('Q');
  standend();
  addch(']');
  move(ypos,6);
  addstr(msg("protokoll_c",2,lang));
  key = getkeyonprompt(msg("protokoll_c",3,lang), cset, TRUE, FALSE,
                       "proto", confrecord);
  if (key==ESCAPE_KEY || key=='Q')  return(0);
  k = 1;
  if (key == 'A') {
    strcat(cmd," k");
  }
  else if (key == 'B') {
    strcat(cmd," z");
  }
  else {
    k = 0;
  }
  return(k);
}


int term_c(char cmd[], confrecordtyp *confrecord)
{
  int lang, n, x_p, y_p;
  boolean notexists, action = FALSE;
  char buf[S_STRLEN+1], str[3*S_STRLEN+1], cstr[S_STRLEN+1], *sp, key;
  tlistetyp *tliste = (tlistetyp *)0;

  lang = confrecord->userrecord.lang;

  n = 0;
  if (*confrecord->termtable != '\0') {
    if ((sp=selectterm_c(confrecord->termtable,confrecord)) != NULL) {
      if (termexists(sp)) {
        strcpy(buf,sp);
        n = 1;
      }
      else {
        errormsg(E_LOGFILE|E_USER|E_CONSOLE,confrecord,"bbs","term_c",
	         "Wrong termtype %s\nin termfile %s",sp,confrecord->termtable);
      }
    }
  }

  move(0,0);
  clear();
  standout();
  addstr(msg("term_c",4,lang));
  standend();
  printw(msg("term_c",5,lang));
  printw(msg("term_c",0,lang),confrecord->userrecord.term);
  strcpy(str," ");
  if (n == 0) {
    do {
      refresh();
      getyx(stdscr,y_p,x_p);
      n = readfromuser(buf, NULL, S_STRLEN, TRUE, confrecord);
      if (n>0 && ! termexists(buf)) {
	notexists = TRUE;
	printw(msg("term_c",1,lang),buf);
      }
      else {
	notexists = FALSE;
      }
    } while (notexists);
  }
  else {
    printw("%s\n",buf);
  }
  if (n > 0) {
    action = TRUE;
  }
  else {
    strcpy(buf,confrecord->userrecord.term);
    move(y_p,x_p);
    addstr(buf);
  }
  strcat(str,buf);

  printw(msg("term_c",2,lang),confrecord->userrecord.lines);
  refresh();
  strcat(str," ");
  getyx(stdscr,y_p,x_p);
  if (readfromuser(buf, NULL, S_STRLEN, TRUE, confrecord) > 0) {
    action = TRUE;
  }
  else {
    sprintf(buf,"%d",confrecord->userrecord.lines);
    move(y_p,x_p);
    addstr(buf);
  }
  strcat(str,buf);
    
  printw(msg("term_c",3,lang),confrecord->userrecord.columns);
  refresh();
  strcat(str," ");
  getyx(stdscr,y_p,x_p);
  if (readfromuser(buf, NULL, S_STRLEN, TRUE, confrecord) > 0) {
    action = TRUE;
  }
  else {
    sprintf(buf,"%d",confrecord->userrecord.columns);
    move(y_p,x_p);
    addstr(buf);
  }
  strcat(str,buf);

  for (n=0; charsets[n] != NULL; n++) {
    strcpy(cstr,"F");
    strcat(cstr,charsets[n]);
    addstrtoliste(&tliste,TRUE,n,TL_BLOCKLEN,cstr,confrecord);
  }
  key = selectpager_c(tliste,n,msg("term_c",6,lang),NULL,TRUE,"charset",
                      confrecord);
  if (key != ESCAPE_KEY) {
    for (n=0; charsets[n] != NULL; n++) {
      readliste(&tliste,FALSE,n,TL_BLOCKLEN,&sp,confrecord);
      if (*sp == 'T') {
        strcpy(confrecord->userrecord.charset,&sp[1]);
        action = TRUE;
        break;
      }
    }
  }
  removeliste(&tliste,TRUE,TL_BLOCKLEN);

  if (! action) return(0);
  strcat(cmd,str);

  return(3);
}


char *selectterm_c(const char *termfile, const confrecordtyp *confrecord)
{
  int anz, znr, n;
  char key, *sp, *zp[3], zeile[2*S_STRLEN+1];
  static char termname[2*S_STRLEN+3];
  tlistetyp *tliste;
  FILE *fp;

  if (termfile == NULL)  return NULL;
  if ((fp=fopen(termfile,"r")) == NULL) {
    errormsg(E_LOGFILE|E_CONSOLE,confrecord,NULL,"selectterm_c",
             "fopen %s: %m",termfile);
    return(NULL);
  }
  tliste = (tlistetyp *)0;
/*
  addstrtoliste(&tliste,TRUE,0,TL_BLOCKLEN,"",confrecord);
*/
  anz = 0;
  znr = 0;
  while((n=fgetnln(zeile,2*S_STRLEN,fp)) >= 0) {
    znr++;
    if (n > 2*S_STRLEN) {
      errormsg(E_LOGFILE|E_CONSOLE,confrecord,NULL,"selectterm_c",
               "line %i too long",znr);
      return(NULL);
    }
    n = splitstring(zp,zeile,'|',2);
    if (n>0 && *zp[0]!='\0' && *zp[0]!='#') {
#ifdef CHECKTERMTABLE
      if (termexists(zp[0])) {
        if (zp[1] == NULL)  zp[1] = "";
        sprintf(termname,"F%-12s %s",zp[0],zp[1]);
        addstrtoliste(&tliste,TRUE,anz++,TL_BLOCKLEN,termname,confrecord);
      }
      else {
        errormsg(E_LOGFILE|E_CONSOLE,confrecord,NULL,"selectterm_c",
                 "Terminaltype %s does not exist",zp[0]);
      }
#else
      if (zp[1] == NULL)  zp[1] = "";
      sprintf(termname,"F%-12s %s",zp[0],zp[1]);
      addstrtoliste(&tliste,TRUE,anz++,TL_BLOCKLEN,termname,confrecord);
#endif
    }
  }
  fclose(fp);
  
  key = selectpager_c(tliste,anz,msg("selectterm_c",0,
                    confrecord->userrecord.lang),NULL,TRUE,"selectterm",
		    confrecord);
  if (key != ESCAPE_KEY) {
    for (n=0; n<anz; n++) {
      readliste(&tliste,FALSE,n,TL_BLOCKLEN,&sp,confrecord);
      if (*sp == 'T') {
        splitstring(zp,sp,' ',2);
	strcpy(termname,&(zp[0][1]));
	removeliste(&tliste,TRUE,TL_BLOCKLEN);
	return(termname);
      }
    }
  }
  removeliste(&tliste,TRUE,TL_BLOCKLEN);
  if (key == RETURN_KEY) {
    strcpy(termname,confrecord->userrecord.term);
    return(termname);
  }

  return(NULL);
}


int selectdir_c(char argstr[], const chrootrecordtyp *chrootrecord,
		const char *helpcontext, const confrecordtyp *confrecord)
{
  UID_T euid;
  GID_T egid;
  int k, n, dnr, danz, lang, len, maxlen;
  char key, str[S_STRLEN+NAME_MAX+2], *sp;
  char *homedirstr = "FHOME (Homedirectory)";
  const char *csp;
  boolean fullist;
  DIR *dp;
  struct dirent *dirp;
  struct stat stats;
  tlistetyp *tliste;

  lang = confrecord->userrecord.lang;
  fullist = confrecord->userrecord.fullist_on_cd;
  if ((dp=opendir(".")) == NULL) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","selectdir_c","opendir .: %m");
    return(-1);
  }
  euid = geteuid();
  egid = getegid();
  tliste = (tlistetyp *)0;
  dnr = 0;
  addstrtoliste(&tliste,TRUE,dnr,TL_BLOCKLEN,homedirstr,confrecord);
  while ((dirp=readdir(dp)) != NULL) {
    if (strcmp(dirp->d_name,".") == 0) continue;
    if (stat(dirp->d_name,&stats) < 0) {
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","selectdir_c","stat %s: %m",
               dirp->d_name);
      continue;
    }
    if (S_ISDIR(stats.st_mode)) {
      n = getperms(&stats,euid,egid);
      if ((n & PERM_R) && (n & PERM_X)) {
        dnr++;
        strcpy(str,"F");
	strcat(str,dirp->d_name);
        addstrtoliste(&tliste,TRUE,dnr,TL_BLOCKLEN,str,confrecord);
      }
    }
    else if (fullist && S_ISREG(stats.st_mode) &&
             (PERM_R & getperms(&stats,euid,egid))) {
      dnr++;
      sprintf(str,"X(%s)  %s",msg("selectdir_c",2,lang),dirp->d_name);
      addstrtoliste(&tliste,TRUE,dnr,TL_BLOCKLEN,str,confrecord);
    }
  }
  closedir(dp);
  danz = dnr + 1;
  sortliste(tliste,TL_BLOCKLEN,danz,confrecord);

  maxlen = COLS - strlen(msg("selectdir_c",1,lang)) - 2;
  len = strlen(chrootrecord->cwdname);
  if (len > maxlen) {
    maxlen -= 4;
    csp = strchr(chrootrecord->cwdname,'/');
    while (len > maxlen) {
      csp = strchr(++csp,'/');
      if (csp == NULL)  return(-1);
      len = strlen(csp);
    }
    sprintf(str,"%s: ....%s",msg("selectdir_c",1,lang),csp);
  }
  else {
    sprintf(str,"%s: %s",msg("selectdir_c",1,lang),chrootrecord->cwdname);
  }
  key = selectpager_c(tliste,danz,msg("selectdir_c",0,lang),str,TRUE,
		      helpcontext,confrecord);
  
  n = -1;
  if (key != ESCAPE_KEY) {
    for (k=0; k<danz; k++) {
      readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
      if (*sp == 'T') {
        if (strcmp(&(homedirstr[1]),&(sp[1])) == 0) {
          n = 0;
        }
        else {
          strmaxcat(argstr," ",PATH_MAX);
          strmaxcat(argstr,&(sp[1]),PATH_MAX);
	  n = 1;
        }
	break;
      }
    }
  }
  else {
    n = -1;
  }
  removeliste(&tliste,TRUE,TL_BLOCKLEN);
  
  return n;
}


int selectfiles_c(char argstr[], const int maxn, const char *helpcontext,
                  const confrecordtyp *confrecord)
{
  UID_T euid;
  GID_T egid;
  int k, n, fnr, fanz;
  char *sp, key, str[NAME_MAX+2];
  const char *mp;
  DIR *dp;
  struct dirent *dirp;
  struct stat stats;
  tlistetyp *tliste;

  if ((dp=opendir(".")) == NULL) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","selectfiles_c",
             "opendir .: %m");
    return(-1);
  }
  euid = geteuid();
  egid = getegid();
  tliste = (tlistetyp *)0;
/*
  addstrtoliste(&tliste,TRUE,0,TL_BLOCKLEN,"",confrecord);
*/
  fnr = -1;
  while ((dirp=readdir(dp)) != NULL) {
    if (stat(dirp->d_name,&stats) < 0) {
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","selectfiles_c","stat %s: %m",
               dirp->d_name);
      removeliste(&tliste,TRUE,TL_BLOCKLEN);
      closedir(dp);
      return(-1);
    }
    if (S_ISREG(stats.st_mode) && (PERM_R & getperms(&stats,euid,egid))) {
      fnr++;
      strcpy(str,"F");
      strcat(str,dirp->d_name);
      addstrtoliste(&tliste,TRUE,fnr,TL_BLOCKLEN,str,confrecord);
    }
  }
  closedir(dp);
  fanz = fnr + 1;
  sortliste(tliste,TL_BLOCKLEN,fanz,confrecord);

  switch (maxn) {
  case 0:
    mp = msg("selectfiles_c",0,confrecord->userrecord.lang);
    break;
  case 1:
    mp = msg("selectfiles_c",1,confrecord->userrecord.lang);
    break;
  default:
    mp = msg("selectfiles_c",2,confrecord->userrecord.lang);
    break;
  }
  key = selectpager_c(tliste,fanz,mp,NULL, maxn==0, helpcontext,confrecord);
  if (key != ESCAPE_KEY) {
    for (k=0, n=0; k<fanz; k++) {
      readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
      if (*sp == 'T') {
	strmaxcat(argstr," ",ARG_MAX);
	strmaxcat(argstr,&(sp[1]),ARG_MAX);
	n++;
      }
    }
  }
  else {
    n = -1;
  }
  removeliste(&tliste,TRUE,TL_BLOCKLEN);
  
  if (strlen(argstr) + environlen() + 100 > ARG_MAX ||
      n > MAXARGS-1) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","selectfiles_c",
	     msg("selectfiles_c",3,confrecord->userrecord.lang));
    n = -1;
  }
  
  return n;
}


char selectpager_c(tlistetyp *tliste, const int anz, const char *header,
                   const char *subheader, const boolean hotselect,
		   const char *helpcontext, const confrecordtyp *confrecord)
{
  int kopfzeilen, lines, zstep, offset, ypos, kmax, k, n;
  char *zary[MAXMEN], *sp, key;

  clear();
  move(0,0);
  standout();
  addstr(header);
  standend();
  if (subheader != (char *)0) {
    kopfzeilen = 3;
    move(1,0);
    addstr(subheader);
  }
  else {
    kopfzeilen = 2;
  }
  lines = confrecord->userrecord.lines - kopfzeilen -1;
  if (lines > MAXMEN) lines = MAXMEN;
  zstep = lines - 2;
  offset = 0;
  do {
    move(kopfzeilen,0);
    clrtobot();
    kmax = offset+lines > anz ? anz : offset+lines;
    for (k=offset,n=0; k<kmax; k++,n++) {
      ypos = kopfzeilen + k - offset;
      readliste(&tliste,FALSE,k,TL_BLOCKLEN,&(zary[n]),confrecord);
      if (*zary[n]!='X') {
	move(ypos,2);
	addch('[');
	standout();
	addch('A'+k-offset);
	standend();
	addch(']');
      }
      move(ypos,6);
      addstr_withmargin(&(zary[n][1]));
    }
    if (anz > lines) {
      if (offset+lines < anz) {
        n = offset +1;
      }
      else {
        n = 0;
      }
    }
    else {
      n = -1;      
    }
    key = menueselect_c(zary,kmax-offset,n,kopfzeilen,hotselect,helpcontext,
                        confrecord);
    if (key == ALLQUANTOR_KEY) {
      wildcardselect_c(key,tliste,anz,confrecord);
    }
    if (pagerstep(key) < 0) {
      offset -= zstep;
    }
    else if (pagerstep(key) > 0) {
      offset += zstep;
    }
    if (alphastep_c(key) > 0) {
      for (k=0; k<anz; k++) {
        readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
        if (*sp && toupper(*(sp+1)) >= key)  break;
      }
      if (k > 0 && *sp && toupper(*(sp+1)) > key)  k--;
      offset = k;
    }
    if (offset > anz-lines) offset = anz-lines;
    if (offset < 0) offset = 0;
  } while (selectpagerquit_c(key) == 0);
  
  return key;
}


char menueselect_c(char *zary[], const int lines, const int position,
                   const int kopfzeilen, const boolean hotselect,
		   const char *helpcontext, const confrecordtyp *confrecord)
{
  int n, k, lang;
  boolean canselect;
  char prompt[S_STRLEN+1], keyset[2*MAXMEN+10], lastselkey, key, c;
  
  lang = confrecord->userrecord.lang;
  lastselkey = 'a';
  for (k=0,n=0; n<lines; n++) {
    if (*zary[n] != 'X') {
      lastselkey = 'a' + n;
      keyset[k++] = lastselkey;
    }
  }
  canselect = (k > 0);
  for (n='A'; n<='Z'; n++)  keyset[k++] = n;
  keyset[k++] = SPACE_KEY;
  keyset[k++] = BACKSPACE_KEY;
  keyset[k++] = DELETE_KEY;
  keyset[k++] = NEWLINE_KEY;
  keyset[k++] = RETURN_KEY;
  if (! hotselect)  keyset[k++] = ALLQUANTOR_KEY;
  keyset[k] = '\0';
  if (lines > 0) {
    if (position == 0) {
      strcpy(prompt,msg("menueselect_c",0,lang));
    }
    else if (position == 1) {
      strcpy(prompt,msg("menueselect_c",1,lang));
    }
    else if (position > 0) {
      sprintf(prompt,msg("menueselect_c",2,lang), position);
    }
    else {
      strcpy(prompt,msg("menueselect_c",3,lang));
    }
    if (canselect) {
      strcat(prompt,msg("menueselect_c",5,lang));
      k = strlen(prompt);
      prompt[k++] = toupper(lastselkey);
      if (! hotselect) {
	prompt[k++] = ',';
	prompt[k++] = ALLQUANTOR_KEY;
      }
      prompt[k] = '\0';
      strcat(prompt,"]>");
    }
    else {
      strcat(prompt,msg("menueselect_c",6,lang));
    }
  }
  else {
    strcpy(prompt,msg("menueselect_c",4,lang));
  }
  do {
    for (k=0; k<lines; k++) {
      move(k+kopfzeilen,0);
      c = *zary[k];
      if (c == 'T') {
 	addch('*');
      }
      else if (ispunct(c)) {
        addch(c);
      }
      else {
        addch(' ');
      }
    }
    key = getkeyonprompt(prompt,keyset,FALSE,FALSE,helpcontext,confrecord);
    if (key >= 'a' && key <= 'z') {
      k = key - 'a';
      if (k>=0 && k<lines) {
        c = *zary[k];
        if (c == 'F' || ispunct(c)) {
          *zary[k] = 'T';
	  if (hotselect) key = RETURN_KEY;
        }
        else if (c == 'T') {
          *zary[k] = 'F';
        }
      }
    }
  } while (selectpagerquit_c(key) == 0 && pagerstep(key) == 0 &&
           wildcardchar_c(key) == 0 && alphastep_c(key) == 0);
  return key;
}


#ifndef NO_REGCOMP
#define NO_RE_COMP
#endif
int wildcardselect_c(const char key, tlistetyp *f_tliste, const int fanz,
                     const confrecordtyp *confrecord)
{
  int p, k, n, lang;
  char str[STRLEN+1], pattern[STRLEN+1], *sp, c;
#ifndef NO_REGCOMP
  regex_t preg;
  regmatch_t pmatch[1];
#else
#endif
  
  lang = confrecord->userrecord.lang;
  move(LINES-1,0);
  clrtoeol();
  standout();
  addstr(msg("wildcardselect_c",1,lang));
  standend();
  refresh();
  c = bbsgetch(TRUE);
  if (c == '?') {
#ifndef NO_REGCOMP
    writetouser(confrecord,msg("wildcardselect_c",2,lang));
#else
#ifndef NO_RE_COMP
    writetouser(confrecord,msg("wildcardselect_c",3,lang));
#endif
#endif
    refresh();
    c = bbsgetch(TRUE);
  }
  if (c == ESCAPE_KEY || c == RETURN_KEY || c == NEWLINE_KEY) {
    return(0);
  }
  else {
    str[0] = c;
    str[1] = '\0';
    if (readfromuser(str,str,STRLEN,TRUE,confrecord) == 0)  return 0;
  }
/*
  k = 0;
  while (c!=ESCAPE_KEY && c!=RETURN_KEY && c!=NEWLINE_KEY && k<STRLEN) {
    if (k>0 && (c==BACKSPACE_KEY || c==DELETE_KEY)) {
      getyx(stdscr,n,p);
      mvdelch(n,--p);
      k--;
    }
    else {
      addch(c);
      str[k++] = c;
    }
    refresh();
    c = bbsgetch(TRUE);
  };
  if (c == ESCAPE_KEY) return(0);
  str[k] = '\0';
*/

  /* Shell-Metazeichen umwandeln in RE */
  p = 0;
  pattern[p++] = '^';
  k = 0;
  while ((c=str[k++]) != '\0') {
    switch (c) {
    case '.':
      pattern[p++] = '\\';
      pattern[p++] = '.';
      break;
    case '*':
      pattern[p++] = '.';
      pattern[p++] = '*';
      break;
#ifndef NO_REGCOMP
    case '?':
      pattern[p++] = '.';
      break;
#endif
    default:
      pattern[p++] = c;
    }
  }
  pattern[p++] = '$';
  pattern[p] = '\0';

  /* RE compilieren */
#ifndef NO_REGCOMP
  if ((k=regcomp(&preg,pattern,REG_EXTENDED|REG_NOSUB)) != 0) {
    regerror(k,&preg,pattern,STRLEN);
#else
#ifndef NO_RE_COMP
  if ((sp=re_comp(pattern)) != (char *)0) {
    strcpy(pattern,sp);
#endif
#endif
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","wildcardselect_c",
	      msg("wildcardselect_c",0,lang),pattern);
    return(-1);
  }
  for (k=0,n=0; k<fanz; k++) {
    readliste(&f_tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
#ifndef NO_REGCOMP
    if ((p=regexec(&preg,&(sp[1]),0,pmatch,0)) == 0) {
#else
#ifndef NO_RE_COMP
    if ((p=re_exec(&(sp[1]))) == 1) {
#endif
#endif
      n++;
      *sp = (*sp == 'T') ? 'F' : 'T';
    }
#ifndef NO_REGCOMP
    else if (p != REG_NOMATCH) {
      regerror(p,&preg,pattern,STRLEN);
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","wildcardselect_c",
		"regexec: %s",pattern);
      regfree(&preg);
#else
#ifndef NO_RE_COMP
    else if (p < 0) {
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","wildcardselect_c",
		"re_exec: internal error");
#endif
#endif
      return(-1);
    }
  }
#ifndef NO_REGCOMP
  regfree(&preg);
#endif
  return(n);
}


int selectpagerquit_c(const char key)
{
  switch (key) {
  case NEWLINE_KEY:
  case RETURN_KEY:
    return(1);
    break;
  case ESCAPE_KEY:
    return(-1);
    break;
  }
  return(0);
}


int alphastep_c(const char key)
{
  if (key >= 'A' && key <= 'Z')  return 1;
  return 0;
}


int bbsquit_c(char argstr[], const confrecordtyp *confrecord)
{
  char key, cset[] = {'Y','J','N','\0'};
  
  key = getkeyonprompt(msg("bbsquit_c",0,confrecord->userrecord.lang),
                       cset,TRUE,FALSE,"",confrecord);
  if (key != 'Y' && key != 'J') {
    argstr[0] = '\0';
    return(-1);
  }
  return(0);
}


int wildcardchar_c(const char key)
{
  if (key == ALLQUANTOR_KEY) return(1);
  return(0);
}


#ifdef CUSTOM_EDITCMDLINE
keyboardcmd cmdline(posstruct *txt, screenstruct *scr, tlistetyp **tliste,
                    const confrecordtyp *confrecord)
{
  int x_p, y_p, k;
  char *sp, cmd[81];
  const char keyset[] = {'S','A','G','C','?',ESCAPE_KEY,RETURN_KEY,'\0'};
  const char *prompt = "[S]end   [A]bort   [G]oto line   [C]mdline_off   [?]help";

  getyx(stdscr,y_p,x_p);
  scr->showcmdline = TRUE;
  scr->curlines = scr->lines - 1;
  if (y_p == scr->lines - 1) {
    txt->a_offset++;
    scrollok(stdscr,TRUE);
    scroll(stdscr);
    scrollok(stdscr,FALSE);
    move(y_p-1,x_p);
  }
  if (getcmd_on_prompt(cmd,80,prompt,keyset,TRUE,scr)) {
    switch (*cmd) {
    case 'S':
      return QuitEdit;
      break;
    case 'A':
      if (! txt->unsaved)  return AbortEdit;
      if (getcmd_on_prompt(cmd,80,"really abort (your text will be lost) [Y,N]? ",
                           "YJN",TRUE,scr)) {
        if (*cmd != 'N') {
          return AbortEdit;
        }
      }
      break;
    case 'G':
      if (getcmd_on_prompt(cmd,80,"goto line:",NULL,FALSE,scr)) {
        if (strcmp(cmd,"$") != 0) {
          k = atoi(cmd);
        }
        else {
          k = -1;
        }
        text_jump(k,txt,scr,tliste,confrecord);
      }
      break;
    case 'C':
      scr->showcmdline = FALSE;
      scr->curlines = scr->lines;
      move(scr->lines-1,0);
      clrtoeol();
      k = txt->a_offset + scr->lines - 1;
      if ( k < txt->a_zeilen) {
        readliste(tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
        printline(sp);
      }
      move(y_p,x_p);
      break;
    case '?':
      showhelp(scr,confrecord);
      break;
    }
  }
  waitread(STDIN_FILENO,cmd,80,KEYBOARDIN_SEQ_DELAY);
  return NoCmd;
}


void showhelp(const screenstruct *scr, const confrecordtyp *confrecord)
{
  int x_p, y_p;
  char cmd[81];
  const char *keyset = "LM";
  const char *prompt = "help on command-line [L] or on cursor-movement [M] ?";
  const char *cmd_msg = "\
 [S]end mail   : send text to recipients\n\
 [A]bort mail  : discard text and go back to BBS-menu\n\
 [G]oto line   : goto line, line no will be asked for\n\
 [C]mdline_off : switch command-line off. It can be switched on by\n\
                  pressing CTRL-X or Escape\n"; 
  const char *cur_msg = "\
  Besides terminal depended cursor-key movement:\n\
  cursor-left  :  CTRL-B\n\
  cursor-right :  CTRL-F\n\
  cursor-up    :  CTRL-P\n\
  cursor-down  :  CTRL-N\n\
  cursor to line start:  CTRL-A\n\
  cursor to line end  :  CTRL-E\n\
  page-up      :  CTRL-V\n\
  page-down    :  CTRL-W or ESC-v\n\
  delete char left from cursor: DEL or Backspace\n\
  clear (kill) line: CTRL-K\n\
  redraw screen:  CTLR-R";
  
  getyx(stdscr,y_p,x_p);
  if (getcmd_on_prompt(cmd,80,prompt,keyset,TRUE,scr)) {
    switch (*cmd) {
    case 'L':
      windowtext(cmd_msg," EDIT: ",0,confrecord);
      break;
    case 'M':
      windowtext(cur_msg," EDIT: ",0,confrecord);
      break;
    }
  }
  move(y_p,x_p);
  return;
}
#endif

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.