* sysdep.c: added new event hook type EVT_TIMER. Timer event hooks are called
authorArt Cancro <ajc@citadel.org>
Mon, 14 Feb 2000 04:36:14 +0000 (04:36 +0000)
committerArt Cancro <ajc@citadel.org>
Mon, 14 Feb 2000 04:36:14 +0000 (04:36 +0000)
  once per minute by any worker thread.
* msgbase.c: removed dependence on nested functions in CtdlOutputMsg() by
  replacing them with an API call CtdlRedirectOutput() in sysdep.c, which
  can temporarily redirect a session's output to an arbitrary file or socket.
* serv_smtp.c: implemented the purging of messages in the queue for which all
  deliveries have been completed.
* serv_smtp.c: removed temporary 'QQQQ' server command and replaced it with
  a timer event hook that runs the queue once per minute (this needs to be
  made more robust)

citadel/ChangeLog
citadel/housekeeping.c
citadel/msgbase.c
citadel/msgbase.h
citadel/serv_pop3.c
citadel/serv_smtp.c
citadel/server.h
citadel/sysdep.c
citadel/sysdep_decls.h

index cb5efad3fa47063c2be74228de4db6366f2b7e40..8fb8b16d743cbc4e3c91be8ff4bb690a4e8a3fc8 100644 (file)
@@ -1,4 +1,16 @@
 $Log$
+Revision 1.458  2000/02/14 04:36:14  ajc
+* sysdep.c: added new event hook type EVT_TIMER.  Timer event hooks are called
+  once per minute by any worker thread.
+* msgbase.c: removed dependence on nested functions in CtdlOutputMsg() by
+  replacing them with an API call CtdlRedirectOutput() in sysdep.c, which
+  can temporarily redirect a session's output to an arbitrary file or socket.
+* serv_smtp.c: implemented the purging of messages in the queue for which all
+  deliveries have been completed.
+* serv_smtp.c: removed temporary 'QQQQ' server command and replaced it with
+  a timer event hook that runs the queue once per minute (this needs to be
+  made more robust)
+
 Revision 1.457  2000/02/08 21:00:47  ajc
 * Implemented the deprecated "LAST" command in POP3.  Some clients need it.
 * POP3 sessions now set the last-read pointer in Mail>.
@@ -1611,4 +1623,3 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
        * Initial CVS import 
-
index 50deb5f9cdb815fd76730fe3d10331aa976cf22a..fc878b499280850cebfb204abd76c50071de5777 100644 (file)
@@ -97,7 +97,7 @@ void housekeeping_loop(void) {
                        tv.tv_usec = 0;
                        FD_ZERO(&readfds);
                        FD_SET(housepipe[0], &readfds);
-                       select(housepipe[0] + 1, &readfds, 0L, 0L, &tv);
+                       select(housepipe[0] + 1, &readfds, NULL, NULL, &tv);
                        if (FD_ISSET(housepipe[0], &readfds)) {
                                did_something = 1;
                        }
index d53ccce82c97933389b0bce19bbdf7cf426171a6..c0982109108eb5aaa2751dc5b839fb8d8d45822c 100644 (file)
@@ -681,129 +681,15 @@ void CtdlFreeMessage(struct CtdlMessage *msg)
 
 
 /*
- * Get a message off disk.  (returns om_* values found in msgbase.h)
- * 
+ * Callback function for mime parser that wants to display text
  */
-int CtdlOutputMsg(long msg_num,                /* message number (local) to fetch */
-               int mode,               /* how would you like that message? */
-               int headers_only,       /* eschew the message body? */
-               int do_proto,           /* do Citadel protocol responses? */
-               FILE *outfp,
-               int outsock,
-               int crlf                /* Use CRLF newlines instead of LF? */
-) {
-       int a, i, k;
-       char buf[1024];
-       time_t xtime;
-       CIT_UBYTE ch;
-       char allkeys[256];
-       char display_name[256];
-       struct CtdlMessage *TheMessage;
-       char *mptr;
-       char *nl;       /* newline string */
-
-       /* buffers needed for RFC822 translation */
-       char suser[256];
-       char luser[256];
-       char snode[256];
-       char lnode[256];
-       char mid[256];
-       /*                                       */
-
-
-       /* BEGIN NESTED FUNCTION omprintf() */
-       void omprintf(const char *format, ...) {   
-               va_list arg_ptr;   
-               char buf[256];   
-        
-               va_start(arg_ptr, format);   
-               if (vsnprintf(buf, sizeof buf, format, arg_ptr) == -1)
-                       buf[sizeof buf - 2] = '\n';
-               if (outfp != NULL) {
-                       fwrite(buf, strlen(buf), 1, outfp);
-               }
-               else if (outsock >= 0) {
-                       write(outsock, buf, strlen(buf));
-               }
-               else {
-                       client_write(buf, strlen(buf)); 
-               }
-               va_end(arg_ptr);
-       }   
-       /* END NESTED FUNCTION omprintf() */
-
-       /* BEGIN NESTED FUNCTION omfmout() */
-       void omfmout(char *mptr) {
-               int b, c;
-               int real = 0;
-               int old = 0;
-               CIT_UBYTE ch;
-               char aaa[140];
-               char buffer[256];
-
-               strcpy(aaa, "");
-               old = 255;
-               strcpy(buffer, "");
-               c = 1;                  /* c is the current pos */
-
-FMTA:          ch = *mptr++;
-               old = real;
-               real = ch;
-               if (ch <= 0)
-                       goto FMTEND;
-       
-               if (((ch == 13) || (ch == 10)) && (old != 13) && (old != 10))
-                       ch = 32;
-               if (((old == 13) || (old == 10)) && (isspace(real))) {
-                       omprintf("%s", nl);
-                       c = 1;
-               }
-               if (ch > 126)
-                       goto FMTA;
-       
-               if (ch > 32) {
-                       if (((strlen(aaa) + c) > (75)) && (strlen(aaa) > (75))) {
-                               omprintf("%s%s", nl, aaa);
-                               c = strlen(aaa);
-                               aaa[0] = 0;
-                       }
-                       b = strlen(aaa);
-                       aaa[b] = ch;
-                       aaa[b + 1] = 0;
-               }
-               if (ch == 32) {
-                       if ((strlen(aaa) + c) > (75)) {
-                               omprintf("%s", nl);
-                               c = 1;
-                       }
-                       omprintf("%s ", aaa);
-                       ++c;
-                       c = c + strlen(aaa);
-                       strcpy(aaa, "");
-                       goto FMTA;
-               }
-               if ((ch == 13) || (ch == 10)) {
-                       omprintf("%s%s", aaa, nl);
-                       c = 1;
-                       strcpy(aaa, "");
-                       goto FMTA;
-               }
-               goto FMTA;
-
-FMTEND:                omprintf("%s%s", aaa, nl);
-       }
-       /* END NESTED FUNCTION omfmout() */
-
-       /* BEGIN NESTED FUNCTION fixed_output() */
-       /*
-       * Callback function for mime parser that wants to display text
-       */
-       void fixed_output(char *name, char *filename, char *partnum, char *disp,
-                       void *content, char *cbtype, size_t length)
+void fixed_output(char *name, char *filename, char *partnum, char *disp,
+               void *content, char *cbtype, size_t length)
        {
                char *ptr;
                char *wptr;
                size_t wlen;
+               CIT_UBYTE ch;
        
                if (!strcasecmp(cbtype, "multipart/alternative")) {
                        strcpy(ma->prefix, partnum);
@@ -828,8 +714,8 @@ FMTEND:             omprintf("%s%s", aaa, nl);
                        wptr = content;
                        while (wlen--) {
                                ch = *wptr++;
-                               if (ch==10) omprintf("%s", nl);
-                               else omprintf("%c", ch);
+                               if (ch==10) cprintf("\r\n");
+                               else cprintf("%c", ch);
                        }
                }
                else if (!strcasecmp(cbtype, "text/html")) {
@@ -838,18 +724,45 @@ FMTEND:           omprintf("%s%s", aaa, nl);
                        wptr = ptr;
                        while (wlen--) {
                                ch = *wptr++;
-                               if (ch==10) omprintf("%s", nl);
-                               else omprintf("%c", ch);
+                               if (ch==10) cprintf("\r\n");
+                               else cprintf("%c", ch);
                        }
                        phree(ptr);
                }
                else if (strncasecmp(cbtype, "multipart/", 10)) {
-                       omprintf("Part %s: %s (%s) (%d bytes)%s",
-                               partnum, filename, cbtype, length, nl);
+                       cprintf("Part %s: %s (%s) (%d bytes)\r\n",
+                               partnum, filename, cbtype, length);
                }
        }
 
-       /* END NESTED FUNCTION fixed_output() */
+
+/*
+ * Get a message off disk.  (returns om_* values found in msgbase.h)
+ * 
+ */
+int CtdlOutputMsg(long msg_num,                /* message number (local) to fetch */
+               int mode,               /* how would you like that message? */
+               int headers_only,       /* eschew the message body? */
+               int do_proto,           /* do Citadel protocol responses? */
+               int crlf                /* Use CRLF newlines instead of LF? */
+) {
+       int a, i, k;
+       char buf[1024];
+       time_t xtime;
+       CIT_UBYTE ch;
+       char allkeys[256];
+       char display_name[256];
+       struct CtdlMessage *TheMessage;
+       char *mptr;
+       char *nl;       /* newline string */
+
+       /* buffers needed for RFC822 translation */
+       char suser[256];
+       char luser[256];
+       char snode[256];
+       char lnode[256];
+       char mid[256];
+       /*                                       */
 
        lprintf(7, "CtdlOutputMsg() msgnum=%ld, mode=%d\n", 
                msg_num, mode);
@@ -987,7 +900,7 @@ FMTEND:             omprintf("%s%s", aaa, nl);
        strcpy(snode, NODENAME);
        strcpy(lnode, HUMANNODE);
        if (mode == MT_RFC822) {
-               omprintf("X-UIDL: %ld%s", msg_num, nl);
+               cprintf("X-UIDL: %ld%s", msg_num, nl);
                for (i = 0; i < 256; ++i) {
                        if (TheMessage->cm_fields[i]) {
                                mptr = TheMessage->cm_fields[i];
@@ -995,7 +908,7 @@ FMTEND:             omprintf("%s%s", aaa, nl);
                                if (i == 'A') {
                                        strcpy(luser, mptr);
                                } else if (i == 'P') {
-                                       omprintf("Path: %s%s", mptr, nl);
+                                       cprintf("Path: %s%s", mptr, nl);
                                        for (a = 0; a < strlen(mptr); ++a) {
                                                if (mptr[a] == '!') {
                                                        strcpy(mptr, &mptr[a + 1]);
@@ -1004,21 +917,21 @@ FMTEND:          omprintf("%s%s", aaa, nl);
                                        }
                                        strcpy(suser, mptr);
                                } else if (i == 'U')
-                                       omprintf("Subject: %s%s", mptr, nl);
+                                       cprintf("Subject: %s%s", mptr, nl);
                                else if (i == 'I')
                                        strcpy(mid, mptr);
                                else if (i == 'H')
                                        strcpy(lnode, mptr);
                                else if (i == 'O')
-                                       omprintf("X-Citadel-Room: %s%s",
+                                       cprintf("X-Citadel-Room: %s%s",
                                                mptr, nl);
                                else if (i == 'N')
                                        strcpy(snode, mptr);
                                else if (i == 'R')
-                                       omprintf("To: %s%s", mptr, nl);
+                                       cprintf("To: %s%s", mptr, nl);
                                else if (i == 'T') {
                                        xtime = atol(mptr);
-                                       omprintf("Date: %s", asctime(localtime(&xtime)));
+                                       cprintf("Date: %s", asctime(localtime(&xtime)));
                                }
                        }
                }
@@ -1028,10 +941,10 @@ FMTEND:          omprintf("%s%s", aaa, nl);
                if (!strcasecmp(snode, NODENAME)) {
                        strcpy(snode, FQDN);
                }
-               omprintf("Message-ID: <%s@%s>%s", mid, snode, nl);
+               cprintf("Message-ID: <%s@%s>%s", mid, snode, nl);
                PerformUserHooks(luser, (-1L), EVT_OUTPUTMSG);
-               omprintf("From: %s@%s (%s)%s", suser, snode, luser, nl);
-               omprintf("Organization: %s%s", lnode, nl);
+               cprintf("From: %s@%s (%s)%s", suser, snode, luser, nl);
+               cprintf("Organization: %s%s", lnode, nl);
        }
 
        /* end header processing loop ... at this point, we're in the text */
@@ -1057,8 +970,8 @@ FMTEND:            omprintf("%s%s", aaa, nl);
                         */
                        while (ch=*(mptr++), ch!=0) {
                                if (ch==13) ;
-                               else if (ch==10) omprintf("%s", nl);
-                               else omprintf("%c", ch);
+                               else if (ch==10) cprintf("%s", nl);
+                               else cprintf("%c", ch);
                        }
                        if (do_proto) cprintf("000\n");
                        CtdlFreeMessage(TheMessage);
@@ -1076,7 +989,7 @@ FMTEND:            omprintf("%s%s", aaa, nl);
        if (mode == MT_CITADEL)
                if (do_proto) cprintf("text\n");
        if (mode == MT_RFC822) {
-               omprintf("%s", nl);
+               cprintf("%s", nl);
        }
 
        /* If the format type on disk is 1 (fixed-format), then we want
@@ -1089,7 +1002,7 @@ FMTEND:           omprintf("%s%s", aaa, nl);
                        if (ch == 13)
                                ch = 10;
                        if ((ch == 10) || (strlen(buf) > 250)) {
-                               omprintf("%s%s", buf, nl);
+                               cprintf("%s%s", buf, nl);
                                strcpy(buf, "");
                        } else {
                                buf[strlen(buf) + 1] = 0;
@@ -1097,7 +1010,7 @@ FMTEND:           omprintf("%s%s", aaa, nl);
                        }
                }
                if (strlen(buf) > 0)
-                       omprintf("%s%s", buf, nl);
+                       cprintf("%s%s", buf, nl);
        }
 
        /* If the message on disk is format 0 (Citadel vari-format), we
@@ -1108,7 +1021,7 @@ FMTEND:           omprintf("%s%s", aaa, nl);
         * message to the reader's screen width.
         */
        if (TheMessage->cm_format_type == FMT_CITADEL) {
-               omfmout(mptr);
+               memfmout(80, mptr, 0);
        }
 
        /* If the message on disk is format 4 (MIME), we've gotta hand it
@@ -1141,7 +1054,7 @@ void cmd_msg0(char *cmdbuf)
        msgid = extract_long(cmdbuf, 0);
        headers_only = extract_int(cmdbuf, 1);
 
-       CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, NULL, -1, 0);
+       CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0);
        return;
 }
 
@@ -1157,7 +1070,7 @@ void cmd_msg2(char *cmdbuf)
        msgid = extract_long(cmdbuf, 0);
        headers_only = extract_int(cmdbuf, 1);
 
-       CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, NULL, -1, 1);
+       CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1);
 }
 
 
@@ -1209,7 +1122,7 @@ void cmd_msg4(char *cmdbuf)
        long msgid;
 
        msgid = extract_long(cmdbuf, 0);
-       CtdlOutputMsg(msgid, MT_MIME, 0, 1, NULL, -1, 0);
+       CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0);
 }
 
 /*
@@ -1224,7 +1137,7 @@ void cmd_opna(char *cmdbuf)
        msgid = extract_long(cmdbuf, 0);
        extract(desired_section, cmdbuf, 1);
 
-       CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, NULL, -1, 1);
+       CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1);
 }                      
 
 
@@ -2449,7 +2362,7 @@ void CtdlWriteObject(char *req_room,              /* Room to stuff it in */
        FILE *fp, *tempfp;
        char filename[PATH_MAX];
        char cmdbuf[256];
-       int ch;
+       char ch;
        struct quickroom qrbuf;
        char roomname[ROOMNAMELEN];
        struct CtdlMessage *msg;
index 51e104ff99c3e7b80aa2d56faff2452f85cf8b9f..8f46a86030364642ec1bb54b654c06b35189e3ee 100644 (file)
@@ -90,6 +90,4 @@ int CtdlOutputMsg(long msg_num,               /* message number (local) to fetch */
                int mode,               /* how would you like that message? */
                int headers_only,       /* eschew the message body? */
                int do_proto,           /* do Citadel protocol responses? */
-               FILE *outfp,
-               int outsock,
                int crlf);
index e9d42b9b51b758162ac00db1e30cf662c46bdbf4..dd193b7bf98965ca02c7a0e10488992261e818bd 100644 (file)
@@ -131,7 +131,11 @@ void pop3_add_message(long msgnum) {
        POP3->msgs[POP3->num_msgs-1].deleted = 0;
        fp = tmpfile();
        POP3->msgs[POP3->num_msgs-1].temp = fp;
-       CtdlOutputMsg(msgnum, MT_RFC822, 0, 0, fp, 0, 1);
+
+       CtdlRedirectOutput(fp, -1);
+       CtdlOutputMsg(msgnum, MT_RFC822, 0, 0, 1);
+       CtdlRedirectOutput(NULL, -1);
+
        POP3->msgs[POP3->num_msgs-1].rfc822_length = ftell(fp);
 }
 
index b90f7f45faab3c92520620b5d9ecce1acd5379e1..099e0110af6fce5d47f3e4aaeedb207123a69778 100644 (file)
@@ -13,9 +13,9 @@
 #include <sys/wait.h>
 #include <string.h>
 #include <limits.h>
+#include <time.h>
 #include "citadel.h"
 #include "server.h"
-#include <time.h>
 #include "sysdep_decls.h"
 #include "citserver.h"
 #include "support.h"
@@ -848,7 +848,11 @@ void smtp_try(char *key, char *addr, int *status, char *dsn, long msgnum)
        }
 
        /* If we reach this point, the server is expecting data */
-       CtdlOutputMsg(msgnum, MT_RFC822, 0, 0, NULL, sock, 1);
+
+       CtdlRedirectOutput(NULL, sock);
+       CtdlOutputMsg(msgnum, MT_RFC822, 0, 0, 1);
+       CtdlRedirectOutput(NULL, -1);
+
        sock_puts(sock, ".");
        if (sock_gets(sock, buf) < 0) {
                *status = 4;
@@ -884,6 +888,53 @@ void smtp_try(char *key, char *addr, int *status, char *dsn, long msgnum)
 
 
 
+/*
+ * smtp_purge_completed_deliveries() is caled by smtp_do_procmsg() to remove
+ * all of the completed deliveries from a set of delivery instructions.
+ *
+ * It returns the number of incomplete deliveries remaining.
+ */
+int smtp_purge_completed_deliveries(char *instr) {
+       int i;
+       int lines;
+       int status;
+       char buf[1024];
+       char key[1024];
+       char addr[1024];
+       char dsn[1024];
+       int completed;
+       int incomplete = 0;
+
+       lines = num_tokens(instr, '\n');
+       for (i=0; i<lines; ++i) {
+               extract_token(buf, instr, i, '\n');
+               extract(key, buf, 0);
+               extract(addr, buf, 1);
+               status = extract_int(buf, 2);
+               extract(dsn, buf, 3);
+
+               completed = 0;
+
+               if (
+                  (!strcasecmp(key, "local"))
+                  || (!strcasecmp(key, "remote"))
+                  || (!strcasecmp(key, "ignet"))
+                  || (!strcasecmp(key, "room"))
+               ) {
+                       if (status == 2) completed = 1;
+                       else ++incomplete;
+               }
+
+               if (completed) {
+                       remove_token(instr, i, '\n');
+                       --i;
+                       --lines;
+               }
+       }
+
+       return(incomplete);
+}
+
 
 /*
  * smtp_do_procmsg()
@@ -902,6 +953,7 @@ void smtp_do_procmsg(long msgnum) {
        char addr[1024];
        char dsn[1024];
        long text_msgid = (-1);
+       int incomplete_deliveries_remaining;
 
        msg = CtdlFetchMessage(msgnum);
        if (msg == NULL) {
@@ -980,19 +1032,44 @@ void smtp_do_procmsg(long msgnum) {
                phree(results);
        }
 
-       /* Delete the instructions and replace with the updated ones */
-       CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, msgnum, NULL);    
-        msg = mallok(sizeof(struct CtdlMessage));
-       memset(msg, 0, sizeof(struct CtdlMessage));
-       msg->cm_magic = CTDLMESSAGE_MAGIC;
-       msg->cm_anon_type = MES_NORMAL;
-       msg->cm_format_type = FMT_RFC822;
-       msg->cm_fields['M'] = malloc(strlen(instr)+256);
-       sprintf(msg->cm_fields['M'],
-               "Content-type: %s\n\n%s\n", SPOOLMIME, instr);
-       phree(instr);
-       CtdlSaveMsg(msg, "", SMTP_SPOOLOUT_ROOM, MES_LOCAL, 1);
-       CtdlFreeMessage(msg);
+
+
+       /*
+        * Go through the delivery list, deleting completed deliveries
+        */
+       incomplete_deliveries_remaining = 
+               smtp_purge_completed_deliveries(instr);
+
+
+       /*
+        * No delivery instructions remain, so delete both the instructions
+        * message and the message message.
+        */
+       if (incomplete_deliveries_remaining <= 0)  {
+               CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, msgnum, NULL);    
+               CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, text_msgid, NULL);    
+       }
+
+
+       /*
+        * Uncompleted delivery instructions remain, so delete the old
+        * instructions and replace with the updated ones.
+        */
+       if (incomplete_deliveries_remaining > 0) {
+               CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, msgnum, NULL);    
+               msg = mallok(sizeof(struct CtdlMessage));
+               memset(msg, 0, sizeof(struct CtdlMessage));
+               msg->cm_magic = CTDLMESSAGE_MAGIC;
+               msg->cm_anon_type = MES_NORMAL;
+               msg->cm_format_type = FMT_RFC822;
+               msg->cm_fields['M'] = malloc(strlen(instr)+256);
+               sprintf(msg->cm_fields['M'],
+                       "Content-type: %s\n\n%s\n", SPOOLMIME, instr);
+               phree(instr);
+               CtdlSaveMsg(msg, "", SMTP_SPOOLOUT_ROOM, MES_LOCAL, 1);
+               CtdlFreeMessage(msg);
+       }
+
 }
 
 
@@ -1015,13 +1092,6 @@ void smtp_do_queue(void) {
 }
 
 
-/**** FIX  temporary hack to run the queue *****/
-void cmd_qqqq(char *argbuf) {
-       smtp_do_queue();
-       cprintf("%d ok\n", OK);
-}
-
-
 
 /*****************************************************************************/
 /*                      MODULE INITIALIZATION STUFF                          */
@@ -1035,11 +1105,8 @@ char *Dynamic_Module_Init(void)
        CtdlRegisterServiceHook(SMTP_PORT,
                                smtp_greeting,
                                smtp_command_loop);
-
-       /****  FIX ... temporary hack to run the queue ******/
-       CtdlRegisterProtoHook(cmd_qqqq, "QQQQ", "run the queue");  
-
        create_room(SMTP_SPOOLOUT_ROOM, 3, "", 0);
+       CtdlRegisterSessionHook(smtp_do_queue, EVT_TIMER);
        return "$Id$";
 }
 
index 00136f7ea42d45990737df05faa9491e18b0878e..757858aad2d7e26065ff81be201d4f799ef0e9c3 100644 (file)
@@ -91,14 +91,21 @@ struct CitContext {
        char dl_is_net;
        char upload_type;
 
+       /* Redirect this session's output to somewhere else? */
+       FILE *redirect_fp;
+       int redirect_sock;
+
+       /* A linked list of all express messages sent to us. */
        struct ExpressMessage *FirstExpressMessage;
 
+       /* Masquerade... */
        char fake_username[32]; /* Fake username <bc>                */
        char fake_postname[32]; /* Fake postname <bc>                */
        char fake_hostname[25]; /* Name of the fake hostname <bc>    */
        char fake_roomname[ROOMNAMELEN];        /* Name of the fake room <bc> */
 
-       struct CtdlSessData *FirstSessData;     /* Allocated session data */
+       /* Dynamically allocated session data */
+       struct CtdlSessData *FirstSessData;
 };
 
 typedef struct CitContext t_context;
@@ -257,8 +264,8 @@ extern struct SessionFunctionHook *SessionHookTable;
 #define EVT_RWHO       7       /* An RWHO command is being executed */
 
 
-
-
+#define EVT_TIMER      50      /* Timer events are called once per minute
+                                  and are not tied to any session */
 
 /*
  * UserFunctionHook extensions are used for any type of hook which implements
index 35a3d8f43797bd95671f9b60d92fa0a075efa258..5c613031302115215174eecb1c8d4a761a31afa0 100644 (file)
@@ -75,6 +75,8 @@ int num_sessions = 0;                         /* Current number of sessions */
 fd_set masterfds;                              /* Master sockets etc. */
 int masterhighest;
 
+time_t last_timer = 0L;                                /* Last timer hook processing */
+
 
 /*
  * lprintf()  ...   Write logging information
@@ -363,13 +365,27 @@ void client_write(char *buf, int nbytes)
 {
        int bytes_written = 0;
        int retval;
+       int sock;
+
+       if (CC->redirect_fp != NULL) {
+               fwrite(buf, nbytes, 1, CC->redirect_fp);
+               return;
+       }
+
+       if (CC->redirect_sock > 0) {
+               sock = CC->redirect_sock;       /* and continue below... */
+       }
+       else {
+               sock = CC->client_socket;
+       }
+
        while (bytes_written < nbytes) {
-               retval = write(CC->client_socket, &buf[bytes_written],
+               retval = write(sock, &buf[bytes_written],
                        nbytes - bytes_written);
                if (retval < 1) {
                        lprintf(2, "client_write() failed: %s\n",
                                strerror(errno));
-                       CC->kill_me = 1;
+                       if (sock == CC->client_socket) CC->kill_me = 1;
                        return;
                }
                bytes_written = bytes_written + retval;
@@ -678,7 +694,35 @@ void dead_session_purge(void) {
 }
 
 
-       
+
+
+
+/*
+ * Redirect a session's output to a file or socket.
+ * This function may be called with a file handle *or* a socket (but not
+ * both).  Call with neither to return output to its normal client socket.
+ */
+void CtdlRedirectOutput(FILE *fp, int sock) {
+
+       if (fp != NULL) CC->redirect_fp = fp;
+       else CC->redirect_fp = NULL;
+
+       if (sock > 0) CC->redirect_sock = sock;
+       else CC->redirect_sock = (-1);
+
+}
+
+
+/*
+ * masterCC is the context we use when not attached to a session.  This
+ * function initializes it.
+ */
+void InitializeMasterCC(void) {
+       memset(&masterCC, 0, sizeof(struct CitContext));
+       masterCC.internal_pgm = 1;
+}
+
+
 
 /*
  * Here's where it all begins.
@@ -697,6 +741,9 @@ int main(int argc, char **argv)
        /* specify default port name and trace file */
        strcpy(tracefile, "");
 
+       /* initialize the master context */
+       InitializeMasterCC();
+
        /* parse command-line arguments */
        for (a=1; a<argc; ++a) {
 
@@ -905,8 +952,13 @@ void worker_thread(void) {
        struct sockaddr_in fsin;        /* Data for master socket */
        int alen;                       /* Data for master socket */
        int ssock;                      /* Descriptor for client socket */
+       struct timeval tv;
 
        ++num_threads;
+
+       tv.tv_sec = 60;         /* wake up every minute if no input */
+       tv.tv_usec = 0;
+
        while (!time_to_die) {
 
                /* 
@@ -932,7 +984,7 @@ SETUP_FD:   memcpy(&readfds, &masterfds, sizeof(fd_set) );
                }
                end_critical_section(S_SESSION_TABLE);
 
-               retval = select(highest + 1, &readfds, NULL, NULL, NULL);
+               retval = select(highest + 1, &readfds, NULL, NULL, &tv);
 
                /* Now figure out who made this select() unblock.
                 * First, check for an error or exit condition.
@@ -1038,6 +1090,10 @@ SETUP_FD:        memcpy(&readfds, &masterfds, sizeof(fd_set) );
 
                }
                dead_session_purge();
+               if ((time(NULL) - last_timer) > 60L) {
+                       last_timer = time(NULL);
+                       PerformSessionHooks(EVT_TIMER);
+               }
        }
 
        /* If control reaches this point, the server is shutting down */        
index 8fcbb82e81742dd248c74305f7ebdcdc38dfef14..4cfdb22973dd8df85c8269170b7dec12f14dfbd3 100644 (file)
@@ -20,5 +20,6 @@ void cmd_nset (char *cmdbuf);
 int convert_login (char *NameToConvert);
 void worker_thread (void);
 inline void become_session(struct CitContext *which_con);
+void CtdlRedirectOutput(FILE *fp, int sock);
 
 extern int num_sessions;