/********************************************************************
 * $Author: lindner $
 * $Revision: 1.10 $
 * $Date: 1993/01/17 04:30:38 $
 * $Source: /home/mudhoney/GopherSrc/gopher1.12/gopher/RCS/ourutils.c,v $
 * $State: Rel $
 *
 * Paul Lindner, University of Minnesota CIS.
 *
 * Copyright 1991, 1992 by the Regents of the University of Minnesota
 * see the file "Copyright" in the distribution for conditions of use.
 *********************************************************************
 * MODULE: ourutils.c
 * stuff that doesn't really fit anywhere else.
 *********************************************************************
 * Revision History:
 * $Log: ourutils.c,v $
 * Revision 1.10  1993/01/17  04:30:38  lindner
 * VMSfile() truncates to a legal VMS filename length.
 *
 * Revision 1.9  1993/01/14  21:16:58  lindner
 * New routines to make nice filenames for Unix and VMS.
 * Add return to make screen look nice for VMS pagers.
 *
 * Revision 1.8  1993/01/12  21:45:17  lindner
 * Removed \n from system() calls.
 * Added filter to Save_file for directories and searches
 *
 * Revision 1.7  1993/01/12  18:19:32  lindner
 * Fixed Save_file call in display_file
 *
 * Revision 1.6  1993/01/09  01:37:32  lindner
 * Changed Save_file so that it takes a default filename.
 * Removed some dead code...
 *
 * Revision 1.5  1992/12/31  05:50:03  lindner
 * Added mods for VMS
 *
 * Revision 1.4  1992/12/11  21:19:51  lindner
 * Really fixed RealName this time..  Gotta test these things..
 *
 * Revision 1.3  1992/12/11  20:59:48  lindner
 * Fixed problem with syntax error RealName, grrr
 *
 * Revision 1.2  1992/12/11  20:54:38  lindner
 * Mailing items with quotes in their name now works, added fflush(stdin)
 * everywhere to fix some input processing problems.
 *
 * Revision 1.1  1992/12/10  23:32:16  lindner
 * gopher 1.1 release
 *
 *********************************************************************/


#include "gopher.h"
#ifndef VMS
#include <pwd.h>
#endif
#ifdef mips
char *getenv();
#endif

int
outchar(c)
char c;
{
        /** output the given character.  From tputs... **/
        /** Note: this CANNOT be a macro!              **/

        putc(c, stdout);
	return(c);
}

display_image(Filename, Realname)
  char *Filename, *Realname;
{
     char imagecmd[512];
     
     strcpy(imagecmd, STRget(ImageCommand));
     strcat(imagecmd, " ");
     strcat(imagecmd, Filename);

     CURexit(CursesScreen);
     system(imagecmd);
     CURenter(CursesScreen);

     printf("Press any key to return to gopher: ");
     fflush(stdin);
     fflush(stdout);
     getchar();

}     

display_mime(Filename, Realname)
  char *Filename, *Realname;
{
     char metamailcmd[512];

     strcpy(metamailcmd, STRget(MIMECommand));
     strcat(metamailcmd, " ");
     strcat(metamailcmd, Filename);

     CURexit(CursesScreen);
     system(metamailcmd);
     CURenter(CursesScreen);

     printf("Press any key to return to gopher: ");
     fflush(stdin);
     fflush(stdout);
     getchar();

}     

/*
** This procedure sends a file through the mail.
*/

void
mail_file(Filename, Realname)
  char *Filename, *Realname;
{
     static char *SaveName = NULL;
     char command[512];
     FILE *infile, *mailit;
     char buf[512];
     
     if (SaveName==NULL) {
	  if ((SaveName = (char *) malloc(sizeof(char)*256)) == NULL)
	       perror("Out of memory!");
	  *SaveName = '\0';
     }

     if (CURGetOneOption(CursesScreen, "Mail current document to:", SaveName)<0)
	  return;
     
     if (*SaveName == '\0')
	  return;
     
/*
 * You should be very careful when you add characters to this list..
 * 
 * It could create a nasty security hole!
 */

#define ACHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789%.@!-_"
		    
     if (SecureMode)
	  if ( strspn(SaveName, ACHARS) != strlen(SaveName) ||
	      *SaveName == '-') {
	       puts(CURgetBell(CursesScreen));
	       fflush(stdout);
	       Draw_Status("Address syntax rejected...");
	       refresh();
	       return;
	  }

     if (strchr(Realname, '\"') != NULL)
	  Realname = "Gopher File";
     
     Draw_Status("Mailing File...");
     refresh();
     
#ifdef VMS
     sprintf(command, "%s/subject=\"%s\" %s %s", 
           MAIL_COMMAND, Realname, Filename, SaveName);
     system(command);
#else
     sprintf(command, "%s %s", 
	     MAIL_COMMAND, SaveName);
     
     infile = fopen(Filename, "r");
     mailit = popen(command, "w");
     
     fprintf(mailit, "Subject: %s\n\n", Realname);

     while (readline(fileno(infile), buf, sizeof(buf))) {
	  twirl();
	  fprintf(mailit, "%s", buf);
     }

     pclose(mailit);
     fclose(infile);

#endif

}


/*
 * This fcn transfers a file from a gopher server into f.
 */

boolean
GStoFile(gs, f)
  GopherObj *gs;
  FILE *f;
{
     int numread, sockfd;
     boolean success = TRUE;
     char buf[1024];
     int line = 0;
     

     if ((sockfd = GSconnect(gs)) <0) {
	  check_sock(sockfd, GSgetHost(gs), GSgetPort(gs));
	  return(FALSE);
     }

     /** Send out the request **/
     writestring(sockfd, GSgetPath(gs));
     writestring(sockfd, "\r\n");
	  
     Draw_Status("Receiving file...");
     refresh();
     

     switch (GSgetType(gs)) {

     case A_FILE:
     case A_MACHEX:
	  while (readline(sockfd, buf, sizeof(buf)) > 0) {
	       ZapCRLF(buf);
	       line ++;
	       if (*buf == '.' && *(buf+1) == '\0')
		    break;
	       fputs(buf, f);
	       putc('\n', f);
	       if ((line % 25) == 0)
		    twirl();
	  }

	  break;
	  
     case A_SOUND:
     case A_IMAGE:
     case A_GIF:
     case A_UNIXBIN:
     case A_PCBIN:
	  while ((numread = readn(sockfd, buf, sizeof buf)) > 0) {
	       if (fwrite(buf, numread, 1, f) == 0) {
		    CursesErrorMsg("Problems Writing");
		    closenet(sockfd);
		    return(FALSE);
	       }
	       twirl();
	  }
	  break;
     }

     closenet(sockfd);
     return(TRUE);
}

/*
 * This function makes a nice vms filename.
 */

void
VMSfile(fname)
  char *fname;
{
#ifndef VMS
     return;
#else
     char *cp, *dot;
     int i, j;

     /**** Further tweek VMS names ****/

     /*** Replace illegal characters with dashes ***/
     for (cp = fname; *cp != '\0'; cp++) {
	  switch (*cp) {
	  case ':':
	  case ',':
	  case '\'':
	  case '\"':
	  case '/':
	  case ' ':
	       *cp = '-';
	  }
     }
	       
     /** Replace all but last dot with _'s, or **/
     /** second to last if last char is Z or z **/
     /** e.g., converts foo.tar.Z to foo.tar_Z **/

     dot = fname;
     j = strlen(fname) - 1;
     if ( (dot =strrchr(dot, '.')) != 0) {
	  if (((fname[j] != '.') &&
	       (*(dot+1) == 'Z' || *(dot+1) == 'z')) &&
	      (((cp =strchr(fname, '.')) != NULL) && cp < dot)) {
	       *dot = '_';
	       dot = strrchr(fname, '.');
	  }
	  cp = fname;
	  while ((cp =strchr(cp, '.')) != NULL && cp < dot) {
	       *cp = '_';
	  }
     }

     /** If the filename is longer than 39 characters, truncate,
         keep the extension though.. **/

     if ((j=strlen(fname)) > 37) {
	  fname[39] = '\0';
     }


     /** If there isn't an extension, add a '.', assume we have some space to
      *$^%& around with   **/
     
     if (strrchr(fname, '.') == NULL) {
	  cp = fname +strlen(fname);
	  
	  *cp = '.';
	  *(cp+1) = '\0';
     }

	  
#endif
}
     
void
UNIXfile(fname)
  char *fname;
{
     char *cp;

     for (cp = fname; *cp != '\0'; cp++) {
	  switch (*cp) {
	  case '\'':
	  case '\"':
	  case '/':
	  case ' ':
	       *cp = '-';
	  }
     }

}

/*
 * This procedure prompts the user for a name, checks for pipe characters
 * and ~ characters in the filename and saves the file to disk.
 * 
 * If infile is NULL then contact the server and get the file.
 * 
 * If saveto is non-NULL then don't prompt the user for a filename
 * to save into, just "do it".
 */

void
Save_file(gs, infile, saveto)
  GopherObj *gs;
  char *infile;
  char *saveto;
{
     char    Userfilename[128];
     char    *cp;
     int     sockfd;
     char    buf[1024];
     boolean Openpipe = FALSE;
     FILE    *f;


     switch (GSgetType(gs)) {
     case A_DIRECTORY:
     case A_INDEX:
	  if (infile == NULL)
	       return;
     }

     /*** Construct a nice default filename ***/
     
     if (saveto == NULL) {
	  /*** Let them use the Title ***/
	  strcpy(Userfilename, GSgetTitle(gs));

#ifdef VMS
	  VMSfile(Userfilename);
#else
	  UNIXfile(Userfilename);
#endif

	  if (CURGetOneOption(CursesScreen, "Save in file: ", Userfilename)<0)
	       return;

	  saveto = Userfilename;
     }

     if (*saveto == '\0')
	  return;

#ifndef VMS
     if (*saveto == '|') {
	  /** Open a pipe! **/
	  Openpipe = TRUE;
	  saveto++;
     }
     
     if (*saveto == '~') {
	  /*** Save in our home directory ***/
	  if (*(saveto + 1) == '/' && (cp = getenv("HOME")) != NULL) {
	       /*** Expand ~ to the home directory ***/
	       strcpy(buf,cp);
	       buf[strlen(cp)]='/';
	       strcpy(buf+strlen(cp) +1, saveto+2);
	       strcpy(saveto, buf);
	  } else {
	  /*** Save in someone else's home directory ***/
	       struct passwd *pass;

	       cp = strchr(saveto,'/');
	       *cp = '\0';
	       pass = getpwnam(saveto+1);
	       if (pass != NULL) {
		    /** align in prep for the home dir **/
		    strcpy(buf,pass->pw_dir);
		    buf[strlen(pass->pw_dir)]='/';
		    strcpy(buf+strlen(pass->pw_dir)+1,cp+1);
		    strcpy(saveto,buf);
		    
	       } else {
		    char tmpstr[256];
		    sprintf(tmpstr, "No such user '%s'", saveto+1);
		    CursesErrorMsg(tmpstr);
		    return;
	       }
	  }
     }
#endif

     if (Openpipe)
	  f = popen(saveto, "w+");
     else
	  f = fopen(saveto, "w+");

     if (f == NULL) {
	  char tempstr[128];

	  sprintf(tempstr, "Couldn't create '%s'", saveto);
	  /** Should give better error messages here **/
	  CursesErrorMsg(tempstr);
	  return;
     }
     
     if (infile != NULL) {
	  /** We've already retrieved it, copy it over... **/
	  int oldfd, cc;

	  oldfd = open(infile, O_RDONLY);
	  if (oldfd <0) {
	       CursesErrorMsg("Can't open old file..");
	       if (Openpipe)
		    pclose(f);
	       else
		    fclose(f);
	       return;
	  }
	  
	  while ( (cc=read(oldfd, buf, sizeof buf)) > 0) {
	       if (fwrite(buf, cc, 1, f) <= 0)
		    CursesErrorMsg("Problems Writing");
	       twirl();
	  }
	  if (Openpipe)
	       pclose(f);
	  else
	       fclose(f);

	 close(oldfd);
	 return;

     } else {
	  /** We don't have the file yet, let's get it... **/

	  GStoFile(gs, f);
	  if (Openpipe)
	       pclose(f);
	  else
	       fclose(f);
     }
}
	       

/*
** This procedure exits out of the curses environment and
** displays the file indicated by pathname to the screen
** using a pager command of some sort 
*/

void
display_file(Filename,gs)
  char *Filename;
  GopherObj *gs;
{
     static char command[MAXSTR];
     static char SaveName[MAXSTR];
     int ch;
     int c;

     strcpy(command, STRget(PagerCommand));

     CURexit(CursesScreen);

     /** Execute the PAGER command **/
     strcat(command, " ");
     strcat(command, Filename);

     
     if (strcmp(STRget(PagerCommand), "builtin") != 0)
	  system(command);
     else
	  Ourpager(Filename);

     printf("\nPress <RETURN> to continue");

     if (!SecureMode)
	  printf(", <m> to mail, <s> to save, or <p> to print:");
     else
	  printf(", <m> to mail:");

     fflush(stdin);
     fflush(stdout);
     noecho();
     cbreak();
#ifdef mips
     raw();
#endif

     ch = 0;
     while (ch == 0) {
	  ch=getchar();

	  if (SecureMode) {
	       switch (ch) {
	       case '\n':
	       case '\r':
	       case KEY_ENTER:
	       case ' ':
		    break;
	       case 'm':
#ifdef VMS
                    (void) getchar();
#endif
		    CURenter(CursesScreen);
		    mail_file(Filename, GSgetTitle(gs));
		    break;

	       default:
		    puts(CURgetBell(CursesScreen));
		    fflush(stdout);
		    ch=0;
		    break;
	       }
	  }
	  else {

	       switch(ch) {
	       case '\n':
	       case '\r':
	       case ' ' :
		    break;
	       case 's':
#ifdef VMS
                    (void) getchar();
#endif
		    CURenter(CursesScreen);
		    Draw_Status("Saving File...");
		    refresh();

		    Save_file(gs, Filename,NULL);
		    break;

	       case 'p':
#ifdef VMS
                    (void) getchar();
#endif
		    sprintf(command, "%s %s", STRget(PrinterCommand),
			    Filename);
		    system(command);
		    break;
		    
	       case 'm':
#ifdef VMS
                    (void) getchar();
#endif
                    CURenter(CursesScreen);
		    mail_file(Filename, GSgetTitle(gs));
		    break;
		    
	       default:
		    puts(CURgetBell(CursesScreen));
		    fflush(stdout);
		    ch=0;
		    break;
	       }
	  }
     }
     
     
     tputs(CURgetCLS(CursesScreen),1,outchar);
     fflush(stdout);
}


/*
** This mini pager is intended for people worried about shell escapes from
** more or less or whatever
*/


/*Ourpager(filename)
  char *filename;
{
     FILE *InFile;
     int i;
     char inputline[512], *cp;
     int Done = FALSE;
     char ZeTypedChar;
     
     if ((InFile = fopen(filename, "r")) == NULL)
	  return;

     while (Done == FALSE) {
	  tputs(CURgetCLS(CursesScreen),1,outchar);

	  for (i=0 ; i < LINES-1; i++) {
	       cp = fgets(inputline, 512, InFile);
	       ZapCRLF(inputline);
	       puts(inputline);
	  }

	  printf("----Press <ENTER> for next page, q to exit------");
	  
	  cbreak();
	  ZeTypedChar = getchar();
	  
	  if ((ZeTypedChar == 'q') || (cp == NULL)) {
	       printf("\n");
	       Done = TRUE;
	  }
     }

     cbreak();
     fclose(InFile);
}
*/



/*
 * This allows the user to add or change data in a form.
 *
 * It returns true if the user wants to keep the changes
 * It returns false if the user wants to abort
 *
 */

BOOLEAN
NewForm(ZeForm)
  Form *ZeForm;
{
     static char printstring[WHOLELINE];
     int         i;          /** Acme Buggy whips and integers **/
     char        ch;

     while (1) {

	  DisplayForm(ZeForm);

	  sprintf(printstring, "Press <ESC> to accept fields and continue");

	  CURcenterline(CursesScreen,"Press <ESC> to accept fields and continue", LINES-3);
	  CURcenterline(CursesScreen,"or press <CTRL-A> to abort", LINES-2);

	  refresh();

	  /*** Now get some user input ***/

	  for (i=0; i< ZeForm->numfields; i++) {

	       move(ZeForm->yloc[i],ZeForm->xloc[i] + strlen(ZeForm->tags[i])+2);
	       refresh();
	       echo();

	       ch = CURwgetstr(CursesScreen, stdscr, ZeForm->values[i],80);

	       /*** ESC key ***/
	       if (ch == '\033') {
		    noecho();
		    return(TRUE);
	       }

	       /*** CTRL-A ***/
	       else if (ch == '\001') {
		    noecho();
		    return(FALSE);
	       }

	       noecho();
	  }
	  
     }

}




/*
 * This Displays a form and a "menu".  It displays the Form
 * and then it waits for a keypress.  It returns the value of the
 * key that is pressed.
 */

void
DisplayForm(ZeForm)
  Form *ZeForm;
{
     int         availlines;
     int         optionlen;
     int         i;          /** Acme Buggy whips and integers **/


     clear();
     Draw_Banner();
     CURcenterline(CursesScreen, ZeForm->Title, 2);
     
     availlines = LINES - 6;
     
     /*** Print out the options according to the Form structure ***/
     
     for (i=0; i<ZeForm->numfields; i++) {
	  optionlen = strlen((ZeForm->tags)[i]);
	  mvaddstr(ZeForm->yloc[i],ZeForm->xloc[i], 
		   ZeForm->tags[i]);
	  addch(':');
	  addch(' ');
	  
	  /*** Now add the current value ***/
	  addstr((ZeForm->values)[i]);
     }
     
}

     
void
CursesMsg(Message, title)
  char *Message;
  char *title;
{
     char *mess[2];
     
     mess[0] = Message;
     mess[1] = NULL;

     CURBeep(CursesScreen);

     CURDialog(CursesScreen, title,mess);

     return;

}

void
CursesErrorMsg(Message)
  char *Message;
{
     CursesMsg(Message, "Gopher Error");
}




