home *** CD-ROM | disk | FTP | other *** search
- /********************************************************************
- * lindner
- * 3.11
- * 1993/04/15 22:20:08
- * /home/mudhoney/GopherSrc/CVS/gopher+/gopherd/gopherd.c,v
- * Exp
- *
- * 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: gopherd.c
- * Routines to implement the gopher server.
- *********************************************************************
- * Revision History:
- * gopherd.c,v
- * Revision 3.11 1993/04/15 22:20:08 lindner
- * CAPFILES mods
- *
- * Revision 3.10 1993/04/15 04:48:07 lindner
- * Debug code from Mitra
- *
- * Revision 3.9 1993/04/10 06:06:11 lindner
- * Admit1 Fixes for combined public/authed server
- *
- * Revision 3.8 1993/04/07 05:54:39 lindner
- * Fixed dreaded .mindex addition problem
- *
- * Revision 3.7 1993/03/26 19:47:50 lindner
- * Hacks to support wais gateway and gplus indexing
- *
- * Revision 3.6 1993/03/25 21:36:30 lindner
- * Mods for directory/recursive etal
- *
- * Revision 3.5 1993/03/24 22:08:59 lindner
- * Removed unused variable
- *
- * Revision 3.4 1993/03/24 20:23:17 lindner
- * Lots of bug fixes, compressed file support, linger fixes, etc.
- *
- * Revision 3.3 1993/03/01 02:22:40 lindner
- * Mucho additions for admit1 stuff..
- *
- * Revision 3.2 1993/02/19 21:21:11 lindner
- * Fixed problems with signals, problems with gethostbyaddr() and
- * inconsisent behavior that depended on the order of files in a directory.
- *
- * Revision 3.1.1.1 1993/02/11 18:02:55 lindner
- * Gopher+1.2beta release
- *
- * Revision 2.8 1993/02/09 22:14:57 lindner
- * many additions for gopher+ stuff..
- *
- * Revision 2.7 1993/01/30 23:57:44 lindner
- * Added extradata handling, language parsing, Fixed extension adding.
- * Fixes for new secure data method.
- * Enhanced link file processing
- * New fcn GDfromSelstr
- *
- * Revision 2.6 1993/01/12 22:53:28 lindner
- * Merged in 1.2.1.6 into mainline release
- *
- * Revision 2.5 1993/01/12 22:48:56 lindner
- * Fixes for mindexd
- *
- * Revision 2.4 1992/12/29 22:13:14 lindner
- * Further refinements to gopher+ stuff.
- * Integrated mindex into the server.
- *
- * Revision 2.3 1992/12/22 21:59:25 lindner
- * Merged in mtm patches to move kernal code to kernutils.c (rev 1.2.1.x)
- *
- * Revision 2.2 1992/12/22 18:56:38 lindner
- * First working gopher+ server with multiple views. Added Addextension()
- * to get the right filename on the backend. More mods to GDfromUFS()
- *
- * Revision 2.1 1992/12/21 20:09:46 lindner
- * Added much code and made many changes to move to gopher+
- * Added parse_request, removed a lot of html stuff
- * Added GDfromHTML, etc.. Lots o' stuff..
- *
- * Revision 1.2.1.6 1993/01/09 02:37:29 lindner
- * Added ftp gateway logging
- * Changed gethostbyaddr() to work on UNICOS
- *
- * Revision 1.2.1.5 1993/01/05 21:32:25 lindner
- * Fixed printfile() so that it deals with files with a period on a line
- * all by itself correctly. Also removed one writestring() call.
- *
- * Revision 1.2.1.4 1993/01/05 21:10:38 lindner
- * Removed setuid() call that broke when using -u and chroot()
- *
- * Revision 1.2.1.3 1992/12/22 21:55:30 lindner
- * fixed typo, int was meant to be double.. Grrrr
- *
- * Revision 1.2.1.2 1992/12/22 21:48:15 lindner
- * Added extern maxload, fixes bug with previous version...
- *
- * Revision 1.2.1.1 1992/12/21 20:51:52 lindner
- * Moved loadrestrict stuff to kernutils.c, also the server
- * can now restrict for load average from standalone mode.
- *
- * Revision 1.2 1992/12/13 06:13:59 lindner
- * Added code to do readline timeouts <mtm>
- *
- * Revision 1.1 1992/12/10 23:13:27 lindner
- * gopher 1.1 release
- *
- *********************************************************************/
-
-
- /* Originally derived from an
- * Example of server using TCP protocol
- * pp 284-5 Stevens UNIX Network Programming
- */
-
-
- #include "gopherd.h"
- #include "command.h"
-
- #undef stat /** Stupid openers thing..**/
- #include <sys/stat.h>
-
- void LOGGopher();
- GopherDirObj *GDfromSelstr();
- GopherDirObj *GDfromUFS();
-
- static char* Gdefusername = NULL;
-
- extern char *getdesc();
- extern double maxload;
- void Process_Side();
-
- #include "STAarray.h"
- #include "STRstring.h"
-
- /* This function is called on a read timeout from the network */
-
- #include <setjmp.h>
- jmp_buf env;
-
- SIGRETTYPE read_timeout(sig)
- int sig;
- {
- longjmp(env,1);
- }
-
-
- /*
- * This routine finds out the hostname of the server machine.
- * It uses a couple of methods to find the fully qualified
- * Domain name
- */
-
- char *
- GetDNSname(backupdomain)
- char *backupdomain;
- {
- static char DNSname[MAXHOSTNAMELEN];
- struct hostent *hp;
- char *cp;
-
- cp = GDCgetHostname(Config);
- if (*cp != '\0')
- return(cp);
-
- DNSname[0] = '\0';
- /* Work out our fully-qualified name, for later use */
-
- if (gethostname(DNSname, MAXHOSTNAMELEN) != 0) {
- fprintf(stderr, "Cannot determine the name of this host\n");
- exit(-1);
- }
-
- /* Now, use gethostbyname to (hopefully) do a nameserver lookup */
- hp = gethostbyname( DNSname);
-
- /*
- ** If we got something, and the name is longer than hostname, then
- ** assume that it must the the fully-qualified hostname
- */
- if ( hp!=NULL && strlen(hp->h_name) > strlen(DNSname) )
- strncpy( DNSname, hp->h_name, MAXHOSTNAMELEN );
- else
- strcat(DNSname, backupdomain);
-
- return(DNSname);
- }
-
-
- /*
- * Tries to figure out what the currently connected port is.
- *
- * If it's a socket then it will return the port of the socket,
- * if it isn't a socket then it returns -1.
- */
-
- int
- GetPort(fd)
- int fd;
- {
- struct sockaddr_in serv_addr;
-
- int length = sizeof(serv_addr);
-
- /** Try to figure out the port we're running on. **/
-
- if (getsockname(fd, (struct sockaddr *) &serv_addr,&length) == 0)
- return(ntohs(serv_addr.sin_port));
- else
- return(-1);
-
- }
-
-
- /*
- * This function returns a socket file descriptor bound to the given port
- */
-
- int
- bind_to_port(port)
- int port;
- {
- struct sockaddr_in serv_addr;
- struct linger linger;
- int reuseaddr = 1;
- int sockfd;
-
-
- if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- err_dump("server: can't open stream socket");
-
- /** Bind our local address so that the client can send to us **/
-
- bzero((char *) &serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- serv_addr.sin_port = htons(port);
-
- if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr,
- sizeof(reuseaddr)) < 0)
- err_dump("server: can't set REUSEADDR!");
-
- if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <0)
- err_dump("server: can't bind local address");
-
- linger.l_onoff = linger.l_linger = 0;
- if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *)&linger,
- sizeof (linger)) < 0)
- err_dump("server: can't turn off linger sockopt");
-
- return(sockfd);
- }
-
-
- void
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int childpid;
- int sockfd, newsockfd;
- int clilen;
- struct sockaddr_in cli_addr;
- boolean OptionsRead = FALSE;
-
-
- /*** for getopt processing ***/
- int c;
- extern char *optarg;
- extern int optind;
- int errflag =0;
-
- /* socket options */
- struct linger linger;
-
- pname = argv[0];
- strcpy(Data_Dir, DATA_DIRECTORY);
- err_init(); /* openlog() early - before we chroot() of course */
-
- /*** Check argv[0], see if we're running as gopherls, etc. ***/
-
- RunServer = RunLS = RunIndex = FALSE;
-
- if (strstr(argv[0], "gopherls") != NULL) {
- RunLS = TRUE;
- } else if (strstr(argv[0], "gindexd") != NULL) {
- RunIndex = TRUE;
- dochroot = FALSE;
- } else
- RunServer = TRUE; /** Run the server by default **/
-
- Config = GDCnew(); /** Set up the general configuration **/
-
- while ((c = getopt(argc, argv, "mCDIcL:l:o:u:")) != -1)
- switch (c) {
- case 'D':
- DEBUG = TRUE;
- break;
-
- case 'I':
- RunFromInetd = TRUE;
- break;
-
- case 'C':
- Caching = FALSE;
- break;
-
- case 'm':
- if (RunIndex)
- MacIndex = TRUE;
- break;
-
- case 'c':
- dochroot = FALSE;
- if (!RunFromInetd) {
- printf("Not using chroot() - be careful\n");
- if ( getuid() == 0 || geteuid() == 0 )
- printf("You should run without root perms\n");
- }
- break;
-
- case 'L': /** Load average at which to restrict usage **/
- maxload = atof(optarg);
- break;
-
- case 'l': /** logfile name **/
- if (*optarg == '/')
- GDCsetLogfile(Config, optarg);
- else {
- char tmpstr[256];
-
- getwd(tmpstr);
- strcat(tmpstr, "/");
- strcat(tmpstr, optarg);
-
- GDCsetLogfile(Config, tmpstr);
- }
- break;
-
- case 'o': /** option file **/
- if (*optarg == '/')
- GDCfromFile(Config, optarg);
- else {
- char tmpstr[256];
- getwd(tmpstr);
- strcat(tmpstr, "/");
- strcat(tmpstr, optarg);
- GDCfromFile(Config, tmpstr);
- }
- OptionsRead = TRUE;
- break;
-
- case 'u':
- {
- struct passwd *pw = getpwnam( optarg );
- if ( !pw ) {
- fprintf(stderr,
- "Could not find user '%s' in passwd file\n",
- optarg);
- errflag++;
- } else {
- Gdefusername = optarg;
- if (!RunFromInetd) {
- printf("Running as user '%s'\n",
- optarg);
- }
- }
- }
- break;
-
- case '?':
- case 'h':
- errflag++;
- break;
- }
- if (errflag) {
- /* Distribution has Usage for older versions of gopher, doesnt
- * reflect options in newer versions */
- fprintf(stderr, "Usage: %s [-mCDIc] [-u username] [-s securityfile] [-l logfile] [ -L loadavg ] <datadirectory> <port>\n", argv[0]);
- fprintf(stderr, " -C turns caching off\n");
- fprintf(stderr, " -D enables copious debugging info\n");
- fprintf(stderr, " -I enable \"inetd\" mode\n");
- fprintf(stderr, " -c disable chroot(), use secure open routines instead\n");
- fprintf(stderr, " -u specifies the username for use with -c\n");
- fprintf(stderr, " -o override the default options file '%s'\n", CONF_FILE);
- fprintf(stderr, " -l specifies the name of a logfile\n");
- fprintf(stderr, " -L specifies maximum load to run at\n");
- fprintf(stderr, " -m specifies MacIndex, whatever that is\n");
-
- exit(-1);
- }
-
- /* if (uid == -2)
- uid = getuid(); /** Run as current user... **/
-
- if ( getuid() == 0 && Gdefusername == NULL)
- printf("Warning! You should run the server with the -u option!\n");
-
-
- if (optind < argc) {
- strcpy(Data_Dir, argv[optind]);
- optind++;
- if (DEBUG)
- printf("main: Setting data to Data Directory is %s\n",Data_Dir);
- } else if (RunLS)
- strcpy(Data_Dir, "/");
-
- if (DEBUG)
- printf("main: Data Directory is %s\n",Data_Dir);
-
- if (optind < argc) {
- GopherPort = atoi(argv[optind]);
- optind++;
- if (DEBUG)
- printf("main: Setting port to %d\n",GopherPort);
- }
- if (DEBUG)
- printf("main: Port is %d\n",GopherPort);
-
- /** Read the options in, if not overridden **/
- if (OptionsRead == FALSE)
- GDCfromFile(Config, CONF_FILE);
-
- /*** Make sure we do a tzset before doing a chroot() ***/
- tzset();
-
-
- if (RunLS) {
- Zehostname =GetDNSname(DOMAIN_NAME);
- Caching = FALSE;
-
- fflush(stdout);
- uchdir(Data_Dir);
-
- listdir(fileno(stdout), "/", FALSE, NULL, NULL);
- exit(0);
- }
-
- if (!RunFromInetd) {
- printf("Gopher Server, Copyright 1991,92 the Regents of the University of Minnesota\n");
- printf("See the file 'Copyright' for conditions of use\n");
- printf("Data directory is %s\n", Data_Dir);
- printf("Port is %d\n", GopherPort);
- }
-
- if (*GDCgetLogfile(Config) != '\0' && !RunFromInetd)
- printf("Logging to File %s\n", GDCgetLogfile(Config));
-
- /*
- * Would like to setuid() here, but have to wait until after the
- * bind() in case we're going to be running on a privileged port.
- */
-
- if (uchdir(Data_Dir)) {
- if (!RunIndex) {
- fprintf(stderr, "Cannot change to data directory!! %s \n",Data_Dir);
- exit(-1);
- }
- }
-
- if (dochroot && getuid() != 0) {
- fprintf(stderr, "Gopherd uses the privileged call chroot(). Please become root.\n");
- exit(-1);
- }
-
- fflush(stderr);
- fflush(stdout);
-
- if (DEBUG == FALSE && RunFromInetd==FALSE)
- daemon_start(0);
-
-
- /*** Hmmm, does this look familiar? :-) ***/
-
-
- err_init(); /* does this look familiar too?? :-) */
-
- /** Ask the system what host we're running on **/
-
- Zehostname = GetDNSname(DOMAIN_NAME);
- if (DEBUG)
- printf("I think your hostname is %s\n", Zehostname);
-
- if (RunFromInetd) {
- /** Ask the system which port we're running on **/
- int newport=0;
- if ((newport =GetPort(0)) !=0)
- GopherPort=newport;
-
- /*** Do the stuff for inetd ***/
-
- while(do_command(fileno(stdout))!=0); /* process the request */
- exit(0);
- }
-
- /** Open a TCP socket (an internet stream socket **/
- sockfd = bind_to_port(GopherPort);
-
- listen(sockfd, 5);
-
- for ( ; ; ) {
- /*
- * Wait for a connection from a client process.
- * This is an example of a concurrent server.
- */
-
- clilen = sizeof(cli_addr);
- newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr,
- &clilen);
-
- linger.l_onoff = linger.l_linger = 0;
- if (setsockopt(newsockfd, SOL_SOCKET, SO_LINGER, (char *)&linger,
- sizeof (linger)) < 0)
- err_dump("server: can't turn off linger sockopt");
-
- if (newsockfd < 0)
- err_dump("server: accept error");
-
- if ( (childpid = fork()) < 0)
- err_dump("server: fork error");
-
- else if (childpid == 0) { /* Child process */
- close(sockfd); /* close original socket */
-
- while(do_command(newsockfd)!=0); /* process the request */
- exit(0);
- }
- /** clean up any zombie children **/
- sig_child();
-
- close(newsockfd); /* parent process */
- }
- }
-
-
-
-
- /*
- * This finds the current peer and the time and jams it into the
- * logfile (if any) and adds the message at the end
- */
-
- void
- LOGGopher(sockfd, message)
- int sockfd;
- char *message;
- {
- static char host_name[256];
- static char ipnum[256];
- time_t Now;
- char *cp;
- /* cp + ' ' + host_name + ' : ' + MAXLINE + '\n' + '\0' */
- char buf[286+MAXLINE];
- struct flock lock;
-
-
- host_name[0] = '\0';
-
- if (LOGFileDesc != -1) {
-
- if (sockfd > -1) {
- inet_netnames(sockfd,host_name, ipnum);
- }
-
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0L;
- lock.l_len = 0L;
- fcntl(LOGFileDesc, F_SETLKW, &lock);
-
- time(&Now); /* Include this in the lock to make sure */
- cp = ctime(&Now); /* log entries are chronological */
- ZapCRLF(cp);
-
- /* someone else may have written to the file since we opened it */
- lseek(LOGFileDesc, 0L, SEEK_END);
-
- sprintf(buf, "%s %d %s : %s\n", cp, getpid(), host_name, message);
- write(LOGFileDesc, buf, strlen(buf));
-
- /* unlock the file */
- lock.l_type = F_UNLCK;
- fcntl(LOGFileDesc, F_SETLKW, &lock);
-
- if (DEBUG)
- printf("%s %d %s : %s\n", cp, getpid(), host_name, message);
-
- }
- }
-
- void
- process_mailfile(sockfd, Mailfname)
- int sockfd;
- char *Mailfname;
- {
- FILE *Mailfile;
- char Zeline[MAXLINE];
- char outputline[MAXLINE];
- char Title[MAXLINE];
- long Startbyte=0, Endbyte=0, Bytecount=0;
- boolean flagged = 0;
-
- if (DEBUG) fprintf(stderr,"process_mailfile %s\r\n",Mailfname);
-
- Mailfile = rfopen(Mailfname, "r");
-
- if (Mailfile == NULL) {
- Abortoutput(sockfd, "Cannot access file");
- return;
- }
-
- while (fgets(Zeline, MAXLINE, Mailfile) != NULL) {
- if (strncmp(Zeline, "Subject: ", 9)==0 && (!flagged)) {
- flagged =1;
- strcpy(Title, Zeline + 9);
- ZapCRLF(Title);
- if (DEBUG)
- fprintf(stderr, "Found title %s\n", Title);
- }
-
- if (is_mail_from_line(Zeline)==0) {
- Endbyte = Bytecount;
- flagged =0;
-
- if (Endbyte != 0) {
- sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n",
- Title, Startbyte, Bytecount, Mailfname,
- Zehostname, GopherPort);
- if (writestring(sockfd, outputline) < 0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
- Startbyte=Bytecount;
- *Title = '\0';
- }
- }
-
- Bytecount += strlen(Zeline);
- }
-
- if (*Title != '\0') {
- sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n",
- Title, Startbyte, Bytecount, Mailfname,
- Zehostname, GopherPort);
- if (writestring(sockfd, outputline)<0)
- LOGGopher(sockfd, "Client went away"),exit(-1);
- }
-
- }
-
-
-
- boolean
- Can_Read(sockfd)
- int sockfd;
- {
- int length;
- char host_name[256];
- char ip[256];
- char *cp;
-
- inet_netnames(sockfd, host_name, ip);
-
- return(GDCCanRead(Config, host_name, ip));
- }
-
- boolean
- Can_Browse(sockfd)
- int sockfd;
- {
- int length;
- char host_name[256];
- char ip[256];
- char *cp;
-
- inet_netnames(sockfd, host_name, ip);
-
- return(GDCCanBrowse(Config, host_name, ip));
- }
-
- boolean
- Can_Search(sockfd)
- int sockfd;
- {
- int length;
- char host_name[256];
- char ip[256];
- char *cp;
- char tmpstr[256];
-
- inet_netnames(sockfd, host_name, ip);
-
- return(GDCCanSearch(Config, host_name, ip));
- }
-
-
-
- char *
- AddExtension(filename, view)
- char *filename;
- char *view;
- {
- boolean status = TRUE;
- Extobj *ext;
- struct stat statbuf;
- static char tmpfilename[256];
-
- if (*filename == '\0')
- return(filename);
-
- ext = EXnew();
-
- strcpy(tmpfilename, filename);
-
- status = EXAviewSearch(Config->Extensions, ext, view);
- if (status == TRUE)
- strcat(tmpfilename, EXgetExt(ext));
-
- if (rstat(tmpfilename+1, &statbuf)) {
- /** Couldn't find the file, return original filename **/
- EXdestroy(ext);
- return(filename);
- } else
- status = FALSE;
-
- EXdestroy(ext);
- return(tmpfilename);
- }
-
-
-
-
- #define DODEBUG(loc) if (DEBUG) { sprintf(debugout,"do_command:%s:Selstr=%s; view=%s;\r\n",loc,Selstr,view); writestring(sockfd,debugout); }
- int
- do_command(sockfd)
- int sockfd;
- {
- char inputline[MAXLINE];
- int length; /* Length of the command line */
- char logline[MAXLINE];
- char *view = NULL;
- char *Selstr = NULL;
- CMDobj *cmd;
- char *filter = NULL;
- TixObj *tix = NULL;
- char debugout[255];
-
- cmd = CMDnew();
-
- /*** Reopen the log file ***/
-
- if (*GDCgetLogfile(Config) != '\0') {
- LOGFileDesc = uopen(GDCgetLogfile(Config), O_WRONLY | O_APPEND |O_CREAT, 0644);
-
- if (LOGFileDesc == -1) {
- printf("Can't open the logfile: %s\n", GDCgetLogfile(Config));
- exit(-1);
- }
- }
-
- DODEBUG("Checking Load")
- if(LoadTooHigh()) {
- Abortoutput(sockfd, "System is too busy right now. Please try again later.");
- exit(-1);
- }
-
-
- (void) signal(SIGALRM,read_timeout);
- (void) alarm(READTIMEOUT);
-
- if(setjmp(env)) {
- LOGGopher(sockfd,"readline: Timed out!");
- Abortoutput(sockfd,"readline: Timed out!");
- exit(-1);
- }
-
- CMDfromNet(cmd, sockfd);
- ASKfile = CMDgetAskfile(cmd);
-
- if (RunIndex) {
- /*** Run like the old gindexd thing. ***/
-
- uchdir("/");
- strcpy(Data_Dir, "/");
-
- if (*CMDgetSelstr(cmd) == '\t')
- Do_IndexTrans(sockfd, Data_Dir, CMDgetSearch(cmd)+1);
- else
- Do_IndexTrans(sockfd, Data_Dir, CMDgetSearch(cmd));
-
- Do_IndexTrans(sockfd, Data_Dir, CMDgetSearch(cmd));
- return(0);
- }
-
-
- #ifdef UMNDES
- if (CMDgetTicket(cmd) != NULL) {
- /*** Test the ticket, and set the appropriate user ***/
- tix=ValidTicket(sockfd, cmd);
-
- if (tix == NULL)
- return(0);
-
- if (Setuid_username(TIXgetUser(tix))==FALSE)
- printf("Failed to set username to %s\n", TIXgetUser(tix));
- if (DEBUG)
- printf("We're now running as uid %d\n", geteuid());
- } else
- /*** No ticket given, default to the defuser ***/
- if (Gdefusername && Setuid_username(Gdefusername) == FALSE) {
- if (DEBUG)
- printf("Couldn't change uid to %s\n",Gdefusername);
- Abortoutput(sockfd, "Can't set UID!"), exit(-1);
- }
- #else
-
-
- if (Gdefusername && Setuid_username(Gdefusername)== FALSE)
- Abortoutput(sockfd, "Can't set UID!"), exit(-1);
- #endif
-
- /** Change our root directory **/
- if ( dochroot ) {
- /** Change back to root for a bit **/
- int tempuid = geteuid();
-
- seteuid(0);
-
- if (chroot(Data_Dir))
- Abortoutput(sockfd, "Data_Dir dissappeared!"), exit(-1);
-
- seteuid(tempuid);
-
- uchdir("/"); /* needed after chroot */
- }
-
-
- /** Extract the view if it exists **/
- if (CMDgetCommand(cmd) != NULL) {
- char *command = CMDgetCommand(cmd);
- if (*command == '+' && strlen(command)>1)
- view = command+1;
- else if (*command == '!') {
- item_info(CMDgetSelstr(cmd), sockfd);
- if (*(command+1) != '\0')
- filter = command + 1;
- return(0);
- }
- else if (*command == '$') {
- if (*(command+1) != '\0')
- filter = command + 1;
- view = "Directory+";
- *command = '+';
- }
- else
- ; /*** Error ***/
- }
-
- if ((strncmp(CMDgetSelstr(cmd), "ftp:",4)==0) ||
- (strncmp(CMDgetSelstr(cmd), "waisdocid:",10)==0))
- view = "Text";
-
- /*** Try to find a view if not supplied ***/
-
- if (view == NULL) {
- GopherDirObj *gd;
- int num,i;
-
-
- /** Get gopher directory containing item in question **/
- gd = GDfromSelstr(CMDgetSelstr(cmd), sockfd);
-
- if (gd != NULL) {
- num = GDSearch(gd, CMDgetSelstr(cmd));
- if (num >=0) {
- GopherObj *gs;
-
- gs= GDgetEntry(gd, num);
-
- /** If only one view, take it **/
- if (GSgetNumViews(gs) == 1)
- view = VIgetViewnLang(GSgetView(gs, 0),(char*)malloc(128));
- else {
- /*** Hmmm, let's choose one.. ***/
- for (i=0; i<GSgetNumViews(gs); i++) {
- char *tmpview;
-
- tmpview = VIgetType(GSgetView(gs,i));
- if (GSgetType(gs) == '0') {
- if (strcmp(tmpview, "Text")==0) {
- view = VIgetViewnLang(GSgetView(gs, i),(char*)malloc(128));
- break;
- }
- }
- if (GSgetType(gs) == 'I') {
- if (strcmp(tmpview, "image/gif")==0) {
- view = VIgetViewnLang(GSgetView(gs, i),(char*)malloc(128));
- break;
- }
- }
-
- }
- if (view == NULL)
- /** Give up, take the first view... **/
- view = VIgetViewnLang(GSgetView(gs,0), (char*)malloc(128));
- }
- /** We should have a view by now **/
- }
- }
- }
-
-
- /** Decide whether to add an extension of not .. **/
- if (view != NULL )
- Selstr = AddExtension(CMDgetSelstr(cmd), view);
- else
- Selstr = CMDgetSelstr(cmd);
-
-
- /*** With the funky new capability system we can just check the
- first letter(s), end decide what the object refers to. ***/
-
- switch (*Selstr) {
- case '\0':
- case '\t':
-
- /*** The null capability, so it's not a file, probably wants
- to talk to a directory server ***/
-
- /*** we'll just do a "list" of the root directory, with no user
- capability. ***/
-
-
- listdir(sockfd, "/", CMDisGplus(cmd), view, filter);
- LOGGopher(sockfd, "Root Connection");
- break;
-
- case 'h':
- /*** A raw html file ***/
- /*** Turn off html'ing and just dump the file ***/
- UsingHTML = FALSE;
-
- case '0':
- case '9':
- case 's':
- case 'I':
- case 'g':
- /*** It's some kind of file ***/
-
- /*** Is it binary?? ***/
- if (view == NULL)
- printfile(sockfd, Selstr+1, 0, -1, CMDisGplus(cmd));
-
-
- if (GSisText(NULL, view))
- printfile(sockfd, Selstr+1, 0, -1, CMDisGplus(cmd));
- else
- echosound(sockfd, Selstr+1, CMDisGplus(cmd));
-
- /*** Log it ***/
- strcpy(logline, "retrieved file ");
- strcat(logline, Selstr+1);
- LOGGopher(sockfd, logline);
- break;
-
-
- case '1':
- /*** It's a directory capability ***/
- listdir(sockfd, Selstr+1, CMDisGplus(cmd), view, filter);
-
- /** Log it **/
- strcpy(logline, "retrieved directory ");
- strcat(logline, Selstr+1);
- LOGGopher(sockfd, logline);
-
- break;
-
- case '7':
- /*** It's an index capability ***/
- if (Can_Search(sockfd) == FALSE) {
- char tmpstr[256];
-
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
-
- sprintf(tmpstr, "Denied access for %s", Selstr+1);
- LOGGopher(sockfd, tmpstr);
- break;
- }
-
- Do_IndexTrans(sockfd, Selstr+1, cmd);
-
- break;
-
-
- case 'm':
- if (strncmp(Selstr, "mindex:", 7)==0) {
- /*** First test for multiple indexes ***/
- if (Can_Search(sockfd) == FALSE) {
- char tmpstr[256];
-
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
-
- sprintf(tmpstr, "Denied access for %s", Selstr+1);
- LOGGopher(sockfd, tmpstr);
- break;
- }
- do_mindexd(sockfd, Selstr+7, CMDgetSearch(cmd));
- break;
- }
-
-
- /*** This is an internal identifier ***/
- /*** The m paired with an Objtype of 1 makes a mail spool file
- into a directory.
- ***/
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", Selstr+1);
- LOGGopher(sockfd, tmpstr);
- break;
- }
-
- process_mailfile(sockfd, Selstr + 1);
- writestring(sockfd, ".\r\n");
-
- /** Log it **/
- strcpy(logline, "retrieved maildir ");
- strcat(logline, Selstr+1);
- LOGGopher(sockfd, logline);
-
- break;
-
- case 'R':
- /*** This is an internal identifier ***/
- /*** The R defines a range ****/
- /*** The format is R<startbyte>-<endbyte>-<filename> **/
- {
- int startbyte, endbyte;
- char *cp, *oldcp;
-
- cp = strchr(Selstr+1, '-');
-
- if (cp == NULL) {
- Abortoutput(sockfd, "Range specifier error");
- break;
- }
-
- *cp = '\0';
- startbyte = atoi(Selstr+1);
- oldcp = cp+1;
-
- cp = strchr(oldcp, '-');
-
- if (cp == NULL) {
- Abortoutput(sockfd, "Range specifier error");
- exit(-1);
- }
-
- *cp = '\0';
- endbyte = atoi(oldcp);
- oldcp = cp + 1;
- if (DEBUG)
- fprintf(stderr, "Start: %d, End: %d File: %s\n", startbyte, endbyte, oldcp);
-
- printfile(sockfd, oldcp, startbyte, endbyte, CMDisGplus(cmd));
-
- /*** Log it ***/
- sprintf(logline, "retrieved range %d - %d of file %s", startbyte, endbyte, oldcp);
- LOGGopher(sockfd, logline);
- break;
- }
-
- case 'f':
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", Selstr);
- LOGGopher(sockfd, tmpstr);
- break;
- }
-
- if (strncmp(Selstr, "ftp:",4)==0){
- sprintf(logline, "retrieved %s", Selstr);
- LOGGopher(sockfd, logline);
-
- SendFtpQuery(sockfd, Selstr+4);
- TranslateResults(sockfd);
- break;
- }
- break;
-
-
- case 'e':
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", Selstr);
- LOGGopher(sockfd, tmpstr);
- break;
- }
-
- if (strncmp(Selstr, "exec:", 5)==0) {
- /* args are between colons */
- char *args, *command;
-
- command = strrchr(Selstr + 5, ':');
- if (command == NULL)
- break;
-
- if (*(Selstr+5) == ':' && *(Selstr+6) == ':')
- args = NULL;
- else
- args = Selstr+5;
-
- *command = '\0';
- command++;
-
- EXECargs = args;
-
- printfile(sockfd, command, 0, -1, CMDisGplus(cmd));
- }
- break;
-
- case 'w':
- {
- if (strncmp(Selstr, "waissrc:", 8) == 0) {
- char waisfname[512]; /*** Ick this is gross ***/
-
- if (Can_Search(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", Selstr);
- LOGGopher(sockfd, tmpstr);
- break;
- }
- strcpy(waisfname, Selstr+8);
- strcat(waisfname, ".src");
- SearchRemoteWAIS(sockfd, waisfname, cmd);
- break;
- }
- else if (strncmp(Selstr, "waisdocid:", 10) == 0) {
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", Selstr);
- LOGGopher(sockfd, tmpstr);
- break;
- }
- Fetchdocid(sockfd, Selstr+10);
- break;
- }
- }
-
-
- default:
- /*** Hmmm, must be an old link... Let's see if it exists ***/
-
- switch (isadir(Selstr)) {
- case -1:
- /* no such file */
- sprintf(logline, "'%s' does not exist", Selstr);
- LOGGopher(sockfd, logline);
- Abortoutput(sockfd, logline);
- break;
-
- case 0:
- /* it's a file */
- printfile(sockfd, Selstr, 0, -1, CMDisGplus(cmd));
-
- /* Log it... */
- strcpy(logline, "retrieved file ");
- strcat(logline, Selstr);
- LOGGopher(sockfd, logline);
-
- break;
-
- case 1:
- /* it's a directory */
- listdir(sockfd, Selstr, CMDisGplus(cmd), view, filter);
-
- /* Log it */
- strcpy(logline, "retrieved directory ");
- strcat(logline, inputline);
- LOGGopher(sockfd, logline);
-
- break;
- }
- }
-
- return(0);
- }
-
-
- /*
- * This function tries to find out what type of file a pathname is.
- */
-
- void
- Getfiletypes(newpath, filename, gs)
- char *newpath;
- char *filename;
- GopherObj *gs;
- {
- int Zefilefd;
- static char Zebuf[256];
- char *cp;
- static char Selstr[512];
-
-
- switch (isadir(filename)) {
- case -1:
- GSsetType(gs,'3');
- return;
-
- case 1:
- GSsetType(gs,A_DIRECTORY);
- *Selstr = '1';
- strcpy(Selstr +1, newpath);
- GSsetPath(gs, Selstr);
- return;
- default:
-
- /*** The default is a generic text file ***/
- GSsetType(gs, A_FILE);
-
- *Selstr = '0';
- strcpy(Selstr + 1, newpath);
-
- /*** Test and see if the thing exists... and is readable ***/
-
- if ((Zefilefd = ropen(filename, O_RDONLY)) < 0) {
- GSsetType(gs, '3');
- return;
- }
-
- if (read(Zefilefd, Zebuf, sizeof(Zebuf)) <0) {
- GSsetType(gs, '3');
- return;
- }
- close(Zefilefd);
-
- /*** Check the first few bytes for sound data ***/
-
- cp = Zebuf;
-
- if (strncmp(cp, ".snd", 4)==0) {
- GSsetType(gs, A_SOUND);
- *Selstr = 's';
- strcpy(Selstr+1, newpath);
- }
-
- /*** Check and see if it's mailbox data ***/
-
- if (is_mail_from_line(Zebuf)==0) {
- GSsetType(gs, A_DIRECTORY);
- *Selstr = 'm';
- strcpy(Selstr+1, newpath);
- GSsetGplus(gs, FALSE); /** Not yet.. **/
- }
-
-
- /*** Check for uuencoding data ***/
-
- if (strncmp(cp,"begin",6) == 0) {
- GSsetType(gs, '6');
- *Selstr = '6';
- strcpy(Selstr+1, newpath);
- }
-
- /*** Check for GIF magic code ***/
-
- if (strncmp(cp, "GIF", 3) == 0) {
- GSsetType(gs, 'I');
- *Selstr = '9';
- strcpy(Selstr + 1, newpath);
- }
-
- GSsetPath(gs, Selstr);
-
- /*** Okay, now let's check for the stuff from gopherd.conf files ***/
-
- }
- }
-
- /*
- * Add a default view if none exists..
- */
-
- void
- AddDefaultView(gs, size, lang)
- GopherObj *gs;
- int size;
- char *lang;
- {
-
- if (lang == NULL)
- lang = GDCgetLang(Config);
-
- switch (GSgetType(gs)) {
- case A_FILE:
- GSaddView(gs, "Text", lang, size);
- break;
- case A_DIRECTORY:
- GSaddView(gs, "Directory", lang, size);
- GSaddView(gs, "Directory+", lang, size);
- break;
- case A_MACHEX:
- GSaddView(gs, "application/binhex", lang, size);
- break;
- case A_PCBIN:
- GSaddView(gs, "application/dos", lang, size);
- break;
- case A_CSO:
- GSaddView(gs, "application/qi", lang, 0);
- break;
- case A_INDEX:
- GSaddView(gs, "Directory", lang, size);
- GSaddView(gs, "Directory+", lang, size);
- break;
- case A_TELNET:
- GSaddView(gs, "application/telnet", lang, 0);
- break;
- case A_SOUND:
- GSaddView(gs, "sound/basic", lang, size);
- break;
- case A_UNIXBIN:
- GSaddView(gs, "application/octet-stream", lang, size);
- break;
- case A_GIF:
- GSaddView(gs, "image/gif", lang, size);
- break;
- case A_HTML:
- GSaddView(gs, "application/HTML", lang, size);
- break;
- case A_TN3270:
- GSaddView(gs, "application/tn3270", lang, 0);
- break;
- case A_MIME:
- GSaddView(gs, "multipart/mixed", lang, size);
- break;
- case A_IMAGE:
- GSaddView(gs, "image", lang, size);
- break;
- }
- }
-
- /*
- * Add a DL description if it's there ...
- */
-
- GStitlefromDL(gs, filename)
- GopherObj *gs;
- char *filename;
- {
- #ifdef DL
- char dlpath[2]; /*** for DL**/
- char *dlout;
-
- /* Process a "dl" description if there is one! */
-
- dlpath[0] = '.';
- dlpath[1] = '\0';
- dlout = getdesc(NULL,dlpath,filename,0);
-
- if (DEBUG)
- printf("dl: %s %s %s\n", dlpath, filename, dlout);
- if (dlout != NULL) {
- GSsetTitle(gs, dlout);
- }
- #endif
- ;
- }
-
-
- /*
- * Load up a gopher directory from the file system
- */
-
- GopherDirObj *
- GDfromUFS(pathname, sockfd, isGplus)
- char *pathname;
- int sockfd;
- boolean isGplus;
- {
- DIR *ZeDir;
- char filename[256];
- static char newpath[512];
- static GopherObj *Gopherstow = NULL;
- static Extobj *ext = NULL;
- GopherObj *gs;
- struct dirent *dp;
- GopherDirObj *gd;
- struct stat statbuf;
- boolean AddItem = TRUE;
- char *Prefix, *View, Gtype, *TheExt;
- static char Pathp[512];
- StrArray *Linkfiles;
- int i, cachefd;
-
- Linkfiles = STAnew(10);
-
- /*** Make our gopherobj ****/
- if (Gopherstow == NULL)
- Gopherstow = GSnew();
-
- gs = Gopherstow;
- if (ext == NULL)
- ext = EXnew();
-
- if (isGplus && GSgplusInited(gs) == FALSE)
- GSplusnew(gs);
-
- gd = GDnew(32);
-
- if (rchdir(pathname)<0) {
- perror("SOL dude");
- exit(-1);
- }
-
-
- if (Caching && Cachetimedout(".cache+", CACHE_TIME, ".")) {
- if ((cachefd = ropen(".cache+", O_RDONLY)) >0) {
- GDplusfromNet(gd, cachefd, NULL);
- return(gd);
- }
- }
-
- /* open "." since we just moved there - makes it work when not
- chroot()ing and using relative paths */
- if ((ZeDir = uopendir(".")) == NULL) {
- char tmpstr[256];
- getwd(tmpstr);
- printf("Current Dir is %s\n", tmpstr);
- fflush(stdout);
- perror("SOL dude");
- sprintf(tmpstr, "Cannot access directory '%s'", pathname);
- Abortoutput(sockfd, tmpstr);
- return(NULL);
- }
-
- for (dp = readdir(ZeDir); dp != NULL; dp = readdir(ZeDir)) {
- #ifdef CAPFILES
- char capfile[MAXPATHLEN];
- int SideFile;
-
- strcpy(capfile,".cap/");
- strcat(capfile, dp->d_name);
- #endif
-
- strcpy(newpath, pathname);
- strcpy(filename, dp->d_name);
- if (newpath[strlen(newpath)-1] != '/')
- strcat(newpath, "/");
- strcat(newpath, dp->d_name);
-
- /* Strip any .Z from newpath before process them
- filename needs to remain as is for type checking */
- if (strcmp(dp->d_name+strlen(dp->d_name)-2,".Z") == 0) {
- newpath[strlen(newpath)-2] = '\0';
- }
- AddItem = TRUE;
- gs = Gopherstow;
-
- if (GDCignore(Config,filename))
- continue;
- else if (filename[0] == '.' &&
- strncmp(filename, ".cache",6) != 0 &&
- isadir(filename)==0) {
-
- String *temp;
-
- /*** This is a link file, process it after other files ***/
-
- temp = STRnew();
- STRset(temp, filename);
-
- STApush(Linkfiles, temp);
- STRdestroy(temp);
- continue;
- } else if (filename[0] == '.') {
- continue;
- }
-
- ustat(filename, &statbuf);
-
- gs = Gopherstow;
- GSinit(gs);
- GSsetHost(gs, Zehostname);
- GSsetPort(gs, GopherPort);
- GSsetGplus(gs, TRUE);
-
- Getfiletypes(newpath, filename, gs);
-
- if (GSgetType(gs) == '3')
- continue;
-
-
- /* If compressed then strip .Z before check for extensions */
- if (strcmp(filename + strlen(filename) -2, ".Z") ==0 &&
- strcmp(filename + strlen(filename) -6, ".tar.Z") != 0)
- filename[strlen(filename) - 2] = '\0';
-
- /*** Add views, prefixes et al.. ***/
- if (GDCBlockExtension(Config, filename, ext)) {
- char tmpstr[256];
- int num;
-
- /** Strip off the extension from the path **/
- *tmpstr = ' ';
- strcpy(tmpstr+1, newpath);
- tmpstr[1+strlen(newpath)-strlen(EXgetExt(ext))]= '\0';
- GSsetPath(gs, tmpstr);
-
- /*** Strip extension off of title ***/
- filename[strlen(filename)-strlen(EXgetExt(ext))]= '\0';
-
- num = GDSearch(gd, GSgetPath(gs));
- if (num != -1) {
- gs = GDgetEntry(gd, num);
- AddItem = FALSE;
- }
-
- if (strcasecmp(EXgetBlockname(ext), "ASK") == 0) {
- GSsetAsk(gs, TRUE);
- }
-
- if (isGplus) {
- GSaddBlock(gs,EXgetBlockname(ext), fixfile(newpath));
- }
- if (AddItem == TRUE)
- GSsetType(gs, '\0');
- }
-
- else if (GDCViewExtension(Config, filename, &ext)) {
- char *cp, *Prefix;
- int num;
-
- Prefix = EXgetPrefix(ext);
-
- strcpy(Pathp, Prefix);
- strcpy(Pathp+strlen(Prefix), newpath);
-
- /*** Strip extension off of pathname***/
- Pathp[strlen(Prefix)+strlen(newpath)-strlen(EXgetExt(ext))]= '\0';
- GSsetPath(gs, Pathp);
- GSsetType(gs, EXgetObjtype(ext));
- /*** Strip extension off of title***/
- filename[strlen(filename)-strlen(EXgetExt(ext))]= '\0';
-
- /**search for existing entry to add a view to **/
- num = GDSearch(gd, Pathp);
- if (num != -1) {
- if (GSgetType(GDgetEntry(gd,num)) == '\0') {
- GSsetHost(gs, NULL);
- GSmerge(GDgetEntry(gd, num), gs);
- }
- gs = GDgetEntry(gd, num);
- AddItem = FALSE;
- }
- if (isGplus) {
- char *lang;
-
- lang = EXgetVLang(ext);
- if (lang == NULL || strcmp(lang, "")==0)
- lang = GDCgetLang(Config);
- GSaddView(gs, EXgetView(ext), lang, statbuf.st_size);
- }
- }
- else if (AddItem) {
- int num;
- char type;
- char *path;
-
- num = GDSearch(gd, GSgetPath(gs));
- if (num != -1) {
- type = GSgetType(gs);
- path = GSgetPath(gs);
- gs = GDgetEntry(gd, num);
- GSsetType(gs, type);
- GSsetPath(gs, path);
- AddItem = FALSE;
- }
- if (isGplus && GSisGplus(gs))
- AddDefaultView(gs, statbuf.st_size, NULL);
- }
-
- if (GSgetTitle(gs) == NULL) {
- /*** Check to see if we have a compressed file ***/
- /* Check moved to further up */
-
- GSsetTitle(gs, filename);
- }
- else
- GSsetTitle(gs, filename);
-
- GStitlefromDL(gs, filename); /** Check DL database for a good name **/
- #ifdef CAPFILES
- if ((SideFile = rfopen(sidename, "r"))!=0) {
- if (DEBUG == TRUE)
- printf("Side file name: %s\n", sidename);
- Process_Side(SideFile, Gopherp);
- close (SideFile);
- }
- #endif
-
- if (isGplus) {
- char tmpstr[256];
- char timeval[16];
- struct tm *tmthing;
-
- if (GSgplusInited(gs) == FALSE)
- GSplusnew(gs);
-
- /*** Add admin, abstract entries, etal ***/
- sprintf(tmpstr, "%s <%s>",
- GDCgetAdmin(Config), GDCgetAdminEmail(Config));
- GSsetAdmin(gs, tmpstr);
-
- /** Set mod date entry **/
- tmthing = localtime(&(statbuf.st_mtime));
- strftime(timeval,sizeof(timeval), "%Y%m%d%H%M%S", tmthing);
- sprintf(tmpstr,"%s<%s>", asctime(tmthing),timeval);
- *(strchr(tmpstr, '\n')) = ' ';
-
- GSsetModDate(gs, tmpstr);
- }
-
- /*** Add the entry to the directory ***/
- if (AddItem) {
- GDaddGS(gd, gs);
- } else
- AddItem = TRUE;
-
-
- }
-
- for (i=0 ; i<STAgetTop(Linkfiles); i++) {
- int linkfd;
-
- linkfd = uopen(STRget(STAgetEntry(Linkfiles,i)), O_RDONLY);
-
- if (linkfd >0) {
- GDfromLink(gd, linkfd, Zehostname, GopherPort, pathname);
- close(linkfd);
- }
- }
-
- closedir(ZeDir);
-
- GDsort(gd);
-
- return(gd);
-
- }
-
-
-
- GopherDirObj *
- GDfromSelstr(selstr,sockfd)
- char *selstr;
- int sockfd;
- {
- char directory[256];
- char *cp;
- GopherDirObj *gd;
-
- /** For now, strip off first character and find the directory above **/
-
- if (DEBUG) fprintf(stderr, "GDfromSelstr:*selstr=%c\r\n",*selstr);
- switch (*selstr) {
- case '0':
- case '1':
- case '7':
- case '9':
- case 's':
- case 'm':
- case 'I':
-
- strcpy(directory, selstr+1);
- break;
-
- case 'R':
- cp = strchr(selstr, '-');
- if (cp == NULL) break;
-
- cp++;
- cp = strchr(cp, '-');
- if (cp == NULL) break;
-
- strcpy(directory, cp+1);
-
- break;
-
- default:
- if (DEBUG) fprintf(stderr,"GDfromSelstr:default\r\n");
- if (*selstr == '\0') {
- strcpy(directory, "//");
- } else {
- cp = strchr(selstr, ':');
- if (cp!=NULL)
- strcpy(directory, cp+1);
- else
- strcpy(directory, selstr);
- }
- }
-
- cp = strrchr(directory, '/');
- if (cp != NULL)
- *(cp+1) = '\0';
-
- if (rchdir(directory)<0) {
- char tmpstr[512];
- sprintf(tmpstr, "- Cannot access directory '%s'", directory);
- Abortoutput(sockfd, tmpstr);
- return(NULL);
- }
-
- gd = GDfromUFS(directory, sockfd, TRUE); /** Returns NULL if error **/
-
- return(gd);
- }
-
-
- /*
- * Send item information to client
- */
- item_info(selstr, sockfd)
- char *selstr;
- int sockfd;
- {
- GopherDirObj *gd;
- GopherObj *gs;
- int num;
- char *cp;
- char tmpstr[256];
-
-
- gd = GDfromSelstr(selstr,sockfd);
- /** For now, strip off first character and find the directory above **/
- /* Note that GDfromSelstr will return NULL (i hope) if cant find dir */
-
- switch (*selstr) {
- case '0':
- case '1':
- case '7':
- case '9':
- case 's':
-
- num = GDSearch(gd, selstr);
- uchdir("/");
-
-
- if (num < 0)
- ; /*** Error message ***/
- else {
- gs = GDgetEntry(gd, num);
- GSsendHeader(sockfd, -2);
- GSplustoNet(gs, sockfd, NULL);
- }
- break;
-
- case '/':
- case '\0':
- gs = GSnew();
- GSsetHost(gs, Zehostname);
- GSsetPort(gs, GopherPort);
- GSsetPath(gs, "");
- GSsetTitle(gs, GDCgetSite(Config));
- GSsetType(gs, '1');
- GSsetGplus(gs, TRUE);
-
- GSsendHeader(sockfd, -2);
- writestring(sockfd, "+INFO ");
- GStoNet(gs,sockfd);
- sprintf(tmpstr, "+ADMIN\r\n Admin: %s <%s>\r\n", GDCgetAdmin(Config),
- GDCgetAdminEmail(Config));
- writestring(sockfd, tmpstr);
- sprintf(tmpstr, " Site: %s\r\n", GDCgetSite(Config));
- writestring(sockfd, tmpstr);
- sprintf(tmpstr, " Org: %s\r\n", GDCgetOrg(Config));
- writestring(sockfd, tmpstr);
- sprintf(tmpstr, " Loc: %s\r\n", GDCgetLoc(Config));
- writestring(sockfd, tmpstr);
- sprintf(tmpstr, " Geog: %s\r\n", GDCgetGeog(Config));
- writestring(sockfd, tmpstr);
-
- writestring(sockfd, "+VIEWS\r\n");
- writestring(sockfd, " Directory: <0k>\r\n");
- writestring(sockfd, " Directory+: <0k>\r\n");
- writestring(sockfd, " Directory/recursive: <0k>\r\n");
- writestring(sockfd, " Directory+/recursive: <0k>\r\n");
-
- break;
- }
- }
-
-
- /*
- ** This function lists out what is in a particular directory.
- ** it also outputs the contents of link files.
- **
- ** It also checks for the existance of a .cache file if caching is
- ** turned on...
- **
- ** Ack is this ugly.
- */
-
- void
- listdir(sockfd, pathname, isgplus, view, filter)
- int sockfd;
- char *pathname;
- boolean isgplus;
- char *view;
- char *filter;
- {
- GopherDirObj *gd;
- boolean attrlist = FALSE;
- boolean Recurse = FALSE;
- char *filtereddata[16], **filtered=filtereddata;
- int i=0;
- StrArray *RecurseDirs;
- String *stapath;
- String *pushstring = STRnew();
-
- if (uchdir("/"))
- perror("SOL dude");
-
- if (filter != NULL) {
- while (*filter != '\0') {
- if (*filter=='+') {
- *filter = '\0';
- filtered[i] = filter+1;
- filter++; i++;
- }
- filter++;
- }
- filtered[i] = NULL;
- } else
- filtered = NULL;
-
-
- if (view != NULL) {
- if (strncmp(view, "Directory+",10) == 0)
- attrlist = TRUE;
- if (strncmp(view, "Directory+/recursive", 20)==0)
- Recurse = TRUE;
- if (strncmp(view, "Directory/recursive", 19)==0)
- Recurse = TRUE;
- }
- if (Recurse)
- RecurseDirs = STAnew(32);
-
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", pathname);
- LOGGopher(sockfd, tmpstr);
- return;
- }
-
-
- if (DEBUG) fprintf(stderr,"listdir: pathname=%s, isgplus=%d, view=%s\r\n",
- pathname, isgplus, view);
- if (rchdir(pathname)<0) {
- if (errno == EACCES)
- #ifdef UMNDES
- PleaseAuthenticate(sockfd);
- #endif
- ;
- Abortoutput(sockfd, "- Cannot access that directory");
- return;
- }
-
- if (isgplus)
- GSsendHeader(sockfd, -1);
-
-
- do {
- if (DEBUG)
- printf("Sending %s\n", pathname);
-
- if (Recurse) {
- rchdir("/");
- if (rchdir(pathname)<0) {
- continue;
- }
- }
-
-
-
- if (Caching) {
-
- if (!attrlist && Cachetimedout(".cache", CACHE_TIME, ".")==FALSE) {
- /*** Old style cache ***/
- printfile(sockfd, ".cache", 0, -1, FALSE);
- return;
- } else if (Cachetimedout(".cache+", CACHE_TIME, ".")==FALSE) {
- /*** Gopher+ cache. ***/
-
- if (strcmp(view, "Directory+")==0) {
- printfile(sockfd, ".cache+", 0, -1, FALSE);
- return;
- } else if (strcmp(view, "Directory")==0) {
- printfile(sockfd, ".cache", 0, -1, FALSE);
- return;
- }
- }
- }
-
- /** If we didn't cache then we have to load up the directory **/
- gd = GDfromUFS(pathname, sockfd, attrlist);
-
- if (gd == NULL) {
- /** Should generate an error message here **/
- return;
- }
-
- rchdir("/");
-
- if (attrlist)
- GDplustoNet(gd, sockfd,filtered);
- else
- GDtoNet(gd, sockfd);
-
-
- /*
- * Write out the cache... *After* we send out the data to the net.
- */
- if (Caching) {
- int cachefd;
- char cachefile[MAXPATHLEN], *cp;
-
- strcpy(cachefile, pathname);
- strcat(cachefile, "/.cache");
-
- cachefd = ropen(cachefile, O_WRONLY|O_CREAT|O_TRUNC, 0644);
-
- if (cachefd != 0) {
- if (DEBUG) {
- printf("Caching directory... into %s\n",cachefile);
- }
- GDtoNet(gd, cachefd);
- close(cachefd);
- }
-
- if (attrlist) {
- strcat(cachefile, "+");
-
- cachefd = ropen(cachefile, O_WRONLY|O_CREAT|O_TRUNC,0644);
-
- if (cachefd) {
- GDplustoNet(gd, cachefd,filtered);
- close(cachefd);
- }
- }
- }
-
-
- if (Recurse) {
- GopherObj *gs;
- /** Push entries on the stack **/
- for (i=0; i< GDgetNumitems(gd); i++) {
- gs = GDgetEntry(gd, i);
- if ((GSgetType(gs) == A_DIRECTORY) &&
- (strcmp(GSgetHost(gs), Zehostname) == 0)) {
- STRset(pushstring, GSgetPath(gs));
- STApush(RecurseDirs, pushstring);
- }
- }
-
- do {
- stapath = STApop(RecurseDirs);
- if (stapath == NULL) {
- Recurse = FALSE; /** Done **/
- break;
- }
- pathname = STRget(stapath);
-
- if (*pathname == 'm')
- process_mailfile(sockfd, pathname+1);
- } while (*pathname == 'm');
-
- pathname++;
-
- }
-
- } while (Recurse);
-
- writestring(sockfd, ".\r\n");
-
- }
-
-
- /*
- * This processes a file containing any subset of
- * Type, Name, Path, Port or Host, and returns pointers to the
- * overriding data that it finds.
- *
- * The caller may choose to initialise the pointers - so we don't
- * touch them unless we find an over-ride.
- */
-
- void
- Process_Side(sidefile, Gopherp)
- FILE *sidefile;
- GopherObj *Gopherp;
- {
- char inputline[MAXLINE];
- char *cp;
-
-
- inputline[0] = '\0';
-
- for (;;) {
- for (;;) {
- cp = fgets(inputline, 1024, sidefile);
- if (inputline[0] != '#' || cp == NULL)
- break;
- }
-
- /*** Test for EOF ***/
- if (cp==NULL)
- break;
-
- ZapCRLF(inputline); /* should zap tabs as well! */
-
- /*** Test for the various field values. **/
-
- if (strncmp(inputline, "Type=", 5)==0) {
- GSsetType(Gopherp, inputline[5]);
- if (inputline[5] == '7') {
- /*** Might as well set the path too... ***/
- *(GSgetPath(Gopherp)) = '7';
- }
- if (inputline[5] == '9') {
- /*** Might as well set the path too... ***/
- *(GSgetPath(Gopherp)) = '9';
- }
- }
-
- else if (strncmp(inputline, "Name=", 5)==0) {
- GSsetTitle(Gopherp, inputline+5);
- }
-
- else if (strncmp(inputline, "Host=", 5)==0) {
- GSsetHost(Gopherp, inputline+5);
- }
-
- else if (strncmp(inputline, "Port=", 5)==0) {
- GSsetPort(Gopherp, atoi(inputline+5));
- }
-
- else if (strncmp(inputline, "Path=", 5)==0) {
- GSsetPath(Gopherp, inputline+5);
- }
-
- else if (strncmp(inputline, "Numb=", 5)==0) {
- GSsetNum(Gopherp, atoi(inputline+5));
- }
-
- else if (strncmp(inputline, "Name=", 5)==0) {
- GSsetTitle(Gopherp, inputline+5);
- }
-
- else if (strncmp(inputline, "Abstract=", 9)==0) {
- GSsetAbstract(Gopherp, inputline+9);
- }
-
- }
-
- fclose(sidefile);
- }
-
-
-
-
-
- /*
- ** This function opens the specified file, starts a zcat if needed,
- ** and barfs the file across the socket.
- **
- ** It now also checks and sees if access is allowed
- **
- */
-
- void
- printfile(sockfd, pathname, startbyte, endbyte, Gplus)
- int sockfd;
- char *pathname;
- int startbyte, endbyte;
- boolean Gplus;
- {
- FILE *ZeFile;
- char inputline[512];
- FILE *pp;
-
-
- /*** Check and see if the peer has permissions to read files ***/
-
- if (Can_Read(sockfd) == FALSE) {
- char tmpstr[256];
- if (writestring(sockfd, GDCgetBummerMsg(Config)) <0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
- writestring(sockfd, "\r\nBummer.....\r\n.\r\n");
- sprintf(tmpstr, "Denied access for %s", pathname);
- LOGGopher(sockfd, tmpstr);
- return;
- }
-
-
- /* Try opening pathname and pathname.Z (or take off .Z if already on) */
-
- if ( (ZeFile = rfopenz(pathname, "r")) == NULL) {
- /*
- * The specified file does not exist
- */
- char notexistline[256];
- sprintf(notexistline, "'%s' does not exist!!", pathname);
- Abortoutput(sockfd, notexistline);
-
- return;
- }
-
- if (startbyte != 0)
- fseek(ZeFile, startbyte, 0);
-
- if (pp = specialfile(ZeFile, pathname)) {
- fclose(ZeFile);
- ZeFile = pp;
- }
-
- if (Gplus)
- GSsendHeader(sockfd, -1);
-
- while (fgets(inputline, sizeof(inputline), ZeFile) != NULL) {
-
- ZapCRLF(inputline);
-
- /** Period on a line by itself, double it.. **/
- if (*inputline == '.' && inputline[1] == '\0') {
- inputline[1] = '.';
- inputline[2] = '\0';
- }
-
- strcat(inputline, "\r\n");
- if (writestring(sockfd, inputline) <0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
-
- if (endbyte >0) {
- if (ftell(ZeFile) >= endbyte)
- break;
- }
- }
-
- Specialclose(ZeFile);
-
- if (writestring(sockfd, ".\r\n")<0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
- }
-
-
- #define BUFSIZE 1523 /* A pretty good value for ethernet */
-
- void
- echosound(sockfd, filename, isGplus)
- int sockfd;
- char *filename;
- boolean isGplus;
- {
-
- FILE *sndfile;
- unsigned char in[BUFSIZE];
- register int j;
- int gotbytes, size;
- struct stat buf;
-
- if (Can_Read(sockfd) == FALSE) {
- char tmpstr[256];
- if (writestring(sockfd, GDCgetBummerMsg(Config)) <0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
- writestring(sockfd, "\r\nBummer.....\r\n.\r\n");
- sprintf(tmpstr, "Denied access for %s", filename);
- LOGGopher(sockfd, tmpstr);
- return;
- }
-
-
- if (strcmp(filename, "-") == 0) {
- /*** Do some live digitization!! **/
- sndfile = popen("record -", "r");
- }
- else
- sndfile = rfopen(filename, "r");
-
- if ((isGplus) && strcmp(filename, "-") == 0)
- GSsendHeader(sockfd, -2);
- else if (isGplus) {
- rstat(filename, &buf);
- size = buf.st_size;
- GSsendHeader(sockfd, size);
- }
-
-
- while(1) {
- gotbytes = fread(in, 1, BUFSIZE, sndfile);
-
- if (gotbytes == 0)
- break; /*** end of file or error... ***/
-
- j = writen(sockfd, in, gotbytes);
-
- if (j == 0)
- break; /*** yep another error condition ***/
-
- }
- }
-
-