/* bkmkfile.c
   Procedures to save and restore bookmarks between Xgopher sessions. */

     /*---------------------------------------------------------------*/
     /* Xgopher        version 1.2     20 November 1991               */
     /*                version 1.1     20 April 1991                  */
     /*                version 1.0     04 March 1991                  */
     /* X window system client for the University of Minnesota        */
     /*                                Internet Gopher System.        */
     /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
     /*                Computing and Communications Services Office   */
     /* Copyright 1992 by                                             */
     /*           the Board of Trustees of the University of Illinois */
     /* Permission is granted to freely copy and redistribute this    */
     /* software with the copyright notice intact.                    */
     /*---------------------------------------------------------------*/


/* Some attempt has been made to make this compatable with the bookmark
   save file used by the curses client.  I can maintain this compatability
   as long as the other client doesn't change too much or too often. */

#include <stdio.h>

#include "bkmkfile.h"
#include "conf.h"
#include "markList.h"
#include "gui.h"
#include "misc.h"
#include "util.h"

#include <pwd.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <errno.h>


	/* In deference to the curses client, we'll attempt to save the
	   resources that are stored in this file that really don't belong
	   there. */

static char	userStuff[USER_STUFF_LEN];

	/* saved status values */

static char	bookmarkFilename[PATH_NAME_LEN] = "";
static BOOLEAN	appendBkmkList = TRUE;


/* setBmkmFile
   Store the name of the bookmark file.  This is initially set by
   resources or defaults, then may be changed by user option. */

void
setBkmkFile(fn)
char	*fn;
{
	strncpy(bookmarkFilename, tildePath(fn), PATH_NAME_LEN);
}


/* setBmkmAppend
   Store the status of the flag that says whether to replace a bookmark
   list when it is read in or to append the bookmark list to existing. */

void
setBkmkAppend(appendFlag)
BOOLEAN	appendFlag;
{
	appendBkmkList = appendFlag;
}


/* bkmkOpen
   return a (possibly invalid) file descriptor of an open bookmark file */

int
bkmkOpen(flags)
int	flags;
{
	struct passwd	*pwdentry;
	char		bkmkFile[PATH_NAME_LEN];
	int		bFD;

	/* see that file exists */

	if (bookmarkFilename[0] == '0') return -1;

	/* find valid directory entry */

	if ((pwdentry = getpwuid( (int) geteuid() ))  == NULL) return -1;

	/* if not an absolute path name, build path name ~/.gopherbk */

	if (bookmarkFilename[0] != '/') {
		strcpy (bkmkFile, pwdentry->pw_dir);
		strcat (bkmkFile, "/");
		strcat (bkmkFile, bookmarkFilename);
		bFD = open(bkmkFile, flags);
	} else {
		bFD = open(bookmarkFilename, flags);
	}

	return bFD;
}


/* bkmkSave
   Save the current bookmark list to the bookmark save file */

void
bkmkSave()
{
	int		bkmkFD;
	char		bkmkFile[PATH_NAME_LEN];
	char		oldBkmkFile[PATH_NAME_LEN];
	gopherItemP	gi;
	struct passwd	*pwdentry;
	char		errorMessage[MESSAGE_STRING_LEN];
	
	/* if secure mode, shouldn't have gotten this far */

	/* see if old file exists */
	/* if not an absolute path name, build path name ~/.gopherbk */

	if (bookmarkFilename[0] != '/') {
		if ((pwdentry = getpwuid( (int) geteuid() ))  == NULL) return;
		strcpy (bkmkFile, pwdentry->pw_dir);
		strcat (bkmkFile, "/");
		strcat (bkmkFile, bookmarkFilename);
	} else {
		strcpy (bkmkFile, bookmarkFilename);
	}

	/* build "backup" path name ~/.gopherbk~ */

	strcpy (oldBkmkFile, bkmkFile);
	strcat (oldBkmkFile, OLD_SUFFIX);

	/* if file exists, rename it to backup file if possible */

	bkmkFD = open(bkmkFile, O_RDONLY);
	if (bkmkFD > -1) {
		close(bkmkFD);
		if (rename(bkmkFile, oldBkmkFile) < 0) {
		    sprintf(errorMessage,
			"Cannot backup old bookmark file: %s to %s",
			bkmkFile, oldBkmkFile);
		    perror("rename");
		    showError(errorMessage);
		    return;
		}
	}
	
	/* open new file */

	bkmkFD = open (bkmkFile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
	if (bkmkFD < 0) {
		sprintf(errorMessage, "Cannot save bookmarks to %s", bkmkFile);
		    perror("open");
		    showError(errorMessage);
		    return;
	}
	
	/* write old user stuff that curses client may need */

	writeString (bkmkFD, userStuff);

	/* write bookmarks */

	gi = firstMark();
	if (gi != NULL) {
		writeString (bkmkFD, "bookmarks:\n");
		for ( ; gi != NULL; gi = gi->next) {
		    char	typeString[2];
		    char	portString[16];

		    typeString[0] = gi->type;
		    typeString[1] = '\0';
		    sprintf (portString, "%d", gi->port);

		    writeString (bkmkFD, "#");
		    writeString (bkmkFD, "\nType=");
		    writeString (bkmkFD, typeString);
		    writeString (bkmkFD, "\nName=");
		    writeString (bkmkFD, USER_STRING(gi));
		    writeString (bkmkFD, "\nPath=");
		    writeString (bkmkFD, vStringValue(&(gi->selector)));
		    writeString (bkmkFD, "\nHost=");
		    writeString (bkmkFD, gi->host);
		    writeString (bkmkFD, "\nPort=");
		    writeString (bkmkFD, portString);
		    writeString (bkmkFD, "\n");
		}
	}

	close(bkmkFD);
}


#define	G_PATH	(1<<0)
#define	G_TYPE  (1<<1)
#define	G_NAME	(1<<2)
#define	G_PORT	(1<<3)
#define	G_HOST	(1<<4)
#define	G_ALL (G_PATH | G_TYPE | G_NAME | G_PORT | G_HOST)

/* readSavedItem
   read a gopher item descriptor from the save file.
   returns pointer to a gopher item with success, NULL on an error.  */

static gopherItemP
readSavedItem(fd, defaultHost, defaultPort)
int	fd;
char	*defaultHost;
int	defaultPort;
{
     int	doneFlags = 0;
     char	buf[1024];
     char	type;
     char	name[1024], path[1024], host[1024];
     int	port;

     while ((doneFlags != G_ALL) && readLine(fd, buf, 1024)) {
	  if (buf[0] == '#')
	       continue;   /* comment */

	  zapCRLF(buf);

	  if (strncmp(buf, "Type=", 5)==0) {
	       type = buf[5];
	       doneFlags |= G_TYPE;
	  }
	  
	  if (strncmp(buf, "Name=", 5)==0) {
	       strcpy(name, buf+5);
	       doneFlags |= G_NAME;
	  }
 	  
	  if (strncmp(buf, "Path=", 5)==0) {
	       strcpy(path, buf+5);
	       doneFlags |= G_PATH;
	  }
 	  
	  if (strncmp(buf, "Host=", 5)==0) {
	       if (buf[5] == '+' && buf[6] == '\0')
	            strcpy(host, defaultHost);
	       else
	            strcpy(host, buf+5);

	       doneFlags |= G_HOST;
	  }
	  if (strncmp(buf, "Port=", 5)==0) {
	       if (buf[5] == '+' && buf[6] == '\0')
		    port = defaultPort;
	       else
		    port = atoi(buf+5);

	       doneFlags |= G_PORT;
	  }
	}

	if (doneFlags == G_ALL) {
	    return (makeItem(type, name, path, host, port, FALSE));
	} else {
	    return NULL;
	}
}


/* bkmkLoad
   Load a previous bookmark list from the bookmark save file */

void
bkmkLoad()
{
	int		bkmkFD;
	char		bkmkFile[PATH_NAME_LEN];
	char		inputLine[FILE_LINE_LEN];
	struct passwd	*pwdentry;
	char		errorMessage[MESSAGE_STRING_LEN];
	int		n;
	gopherItemP	gi;
	

	if ((bkmkFD = bkmkOpen(O_RDONLY)) < 0) return;

	*userStuff = '\0';
	while ((n = readLine(bkmkFD, inputLine, sizeof(inputLine))) > 0) {

		zapCRLF(inputLine);

		if (strncasecmp(inputLine, "bookmarks:", 9) != 0) {

			/*  not a bookmark list, just stash text away */

			if (strlen(userStuff) + n + 1 < USER_STUFF_LEN) {
				strcat(userStuff, inputLine);
				strcat(userStuff, "\n");
			}

		} else {

			/* a bookmark list: load it */
			
			if (! appendBkmkList) unmarkAllItems();
			do {
				gi = readSavedItem(bkmkFD, "localhost", 70);
				if (gi != NULL) markItem(gi);
			} while (gi != NULL);
		}
	}

	close (bkmkFD);
}
