* Fixed the "idle timeout during paginator prompt" bug by reintroducting the
authorArt Cancro <ajc@citadel.org>
Fri, 24 May 2002 19:58:13 +0000 (19:58 +0000)
committerArt Cancro <ajc@citadel.org>
Fri, 24 May 2002 19:58:13 +0000 (19:58 +0000)
  concept of a "half keepalive" and sending them during paginator prompts.

citadel/ChangeLog
citadel/citadel.h
citadel/citserver.c
citadel/commands.c
citadel/ipcdef.h
citadel/routines.c
citadel/serv_info.c
citadel/techdoc/session.txt

index 4a2514f8a8f24b7871739d68adf13c6314792ae6..c5cd6e0908e8eec490224909bd90255203cd2b99 100644 (file)
@@ -1,4 +1,8 @@
  $Log$
+ Revision 591.31  2002/05/24 19:58:13  ajc
+ * Fixed the "idle timeout during paginator prompt" bug by reintroducting the
+   concept of a "half keepalive" and sending them during paginator prompts.
+
  Revision 591.30  2002/05/23 03:33:21  ajc
  * Added a GTSN (GeT list of SeeN messages) command
 
@@ -3675,4 +3679,3 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
        * Initial CVS import
-
index e0119bfffe6fa775ed56a1419eaa701c4bcd660c..841be386040575716fa9afc7ca71f15456a7cab4 100644 (file)
@@ -265,8 +265,11 @@ struct floor {
 #define RC_DEFAULT     2               /* setting depends on user config */
 
 /* keepalives */
-#define KA_NO          0               /* no keepalives */
-#define KA_YES         1               /* full keepalives */
+enum {
+       KA_NO,                          /* no keepalives */
+       KA_YES,                         /* full keepalives */
+       KA_HALF                         /* half keepalives */
+};
 
 /* for <;G>oto and <;S>kip commands */
 #define GF_GOTO                0               /* <;G>oto floor mode */
index 78a0e7e79aba8a1e9a78e858079cc4cff0ab75a2..5aea06c2baef5bc0f72f6747ab1c4e9ecc7b39a2 100644 (file)
@@ -330,6 +330,7 @@ void cmd_info(void) {
        cprintf("1\n"); /* 1 = yes, this system supports floors */
        cprintf("1\n"); /* 1 = we support the extended paging options */
        cprintf("%s\n", CC->cs_nonce);
+       cprintf("1\n"); /* 1 = yes, this system supports the QNOP command */
        cprintf("000\n");
 }
 
@@ -891,9 +892,10 @@ void do_command_loop(void) {
 
        /*
         * Let other clients see the last command we executed, and
-        * update the idle time, but not NOOP, PEXP, or GEXP.
+        * update the idle time, but not NOOP, QNOP, PEXP, or GEXP.
         */
        if ( (strncasecmp(cmdbuf, "NOOP", 4))
+          && (strncasecmp(cmdbuf, "QNOP", 4))
           && (strncasecmp(cmdbuf, "PEXP", 4))
           && (strncasecmp(cmdbuf, "GEXP", 4)) ) {
                strcpy(CC->lastcmdname, "    ");
@@ -912,6 +914,10 @@ void do_command_loop(void) {
        if (!strncasecmp(cmdbuf,"NOOP",4)) {
                cprintf("%d%cok\n",CIT_OK,CtdlCheckExpress());
        }
+       
+       else if (!strncasecmp(cmdbuf,"QNOP",4)) {
+               /* do nothing, this command returns no response */
+       }
 
        else if (!strncasecmp(cmdbuf,"QUIT",4)) {
                cprintf("%d Goodbye.\n",CIT_OK);
index e101b9422a835f51e9e26b7d00a09793fe29049c..09c2bec8c87fe49d85a1c43978e43120023983d6 100644 (file)
@@ -135,7 +135,7 @@ char was_a_key_pressed(void) {
 
 /*
  * Check to see if we need to pause at the end of a screen.
- * If we do, we have to disable server keepalives during the pause because
+ * If we do, we have to switch to half keepalives during the pause because
  * we are probably in the middle of a server operation and the NOOP command
  * would confuse everything.
  */
@@ -154,7 +154,7 @@ int checkpagin(int lp, int pagin, int height)
 
        if (!pagin) return(0);
        if (lp>=(height-1)) {
-               set_keepalives(KA_NO);
+               set_keepalives(KA_HALF);
                hit_any_key();
                set_keepalives(KA_YES);
                return(0);
@@ -348,6 +348,10 @@ static void really_do_keepalive(void) {
        char buf[1024];
 
        time(&idlet);
+
+       /* If full keepalives are enabled, send a NOOP to the server and
+        * wait for a response.
+        */
        if (keepalives_enabled == KA_YES) {
                serv_puts("NOOP");
                serv_gets(buf);
@@ -362,6 +366,14 @@ static void really_do_keepalive(void) {
                        }
                }
        }
+
+       /* If half keepalives are enabled, send a QNOP to the server (if the
+        * server supports it) and then do nothing.
+        */
+       if ( (keepalives_enabled == KA_HALF)
+          && (serv_info.serv_supports_qnop > 0) ) {
+               serv_puts("QNOP");
+       }
 }
 
 /* threaded nonblocking keepalive stuff starts here. I'm going for a simple
index 5acea43a36f8f4658010a4f96ec885818a34f9ec..ba54081d0153b720cd5edce5ab680c8b3015bd95 100644 (file)
@@ -39,7 +39,8 @@ struct CtdlServInfo {
        char serv_moreprompt[256];
        int serv_ok_floors;
        int serv_paging_level;
-       };
+       int serv_supports_qnop;
+};
 
 #define QR_PERMANENT   1               /* Room does not purge              */
 #define QR_INUSE       2               /* Set if in use, clear if avail    */
index 9d75ee47b915139b9c537353e8fd652ad4b7c6b8..2dfcf11f6c88ab5671fc7879005946f7eba68e86 100644 (file)
@@ -64,13 +64,15 @@ extern char rc_floor_mode;
 extern int rc_ansi_color;
 extern int rc_prompt_control;
 
-void back(int spaces) /* Destructive backspace */
-            {
+/* Destructive backspace */
+void back(int spaces) {
        int a;
-       for (a=1; a<=spaces; ++a) {
-               scr_putc(8); scr_putc(32); scr_putc(8);
-               }
+       for (a=0; a<spaces; ++a) {
+               scr_putc(8);
+               scr_putc(32);
+               scr_putc(8);
        }
+}
 
 void hit_any_key(void) {               /* hit any key to continue */
        int a,b;
@@ -170,8 +172,8 @@ AGUP:       snprintf(buf, sizeof buf, "AGUP %s",who);
        serv_gets(buf);
        if (buf[0]!='2') {
                scr_printf("%s\n",&buf[4]);
-               }
        }
+}
 
 
 int set_attr(int sval, char *prompt, unsigned int sbit)
@@ -194,7 +196,7 @@ int set_attr(int sval, char *prompt, unsigned int sbit)
        temp=(temp|sbit);
        if (!a) temp=(temp^sbit);
        return(temp);
-       }
+}
 
 /*
  * modes are:  0 - .EC command, 1 - .EC for new user,
@@ -211,7 +213,7 @@ void enter_config(int mode)
        if (buf[0]!='2') {
                scr_printf("%s\n",&buf[4]);
                return;
-               }
+       }
 
        width = extract_int(&buf[4],0);
        height = extract_int(&buf[4],1);
@@ -295,36 +297,35 @@ int getstring(FILE *fp, char *string)
                        if (c<0) {
                                string[a]=0;
                                return(-1);
-                               }
+                       }
                        string[a++]=c;
-                       } while(c!=10);
+               } while(c!=10);
                        string[a-1]=0;
-               } while(string[0]=='#');
+       } while(string[0]=='#');
        return(strlen(string));
-       }
+}
 
-int pattern(char *search, char *patn)  /* Searches for patn in search string */
-              
-            
-{
+
+/* Searches for patn in search string */
+int pattern(char *search, char *patn) {
        int a,b;
-       for (a=0; a<strlen(search); ++a)
-       {       b=strncasecmp(&search[a],patn,strlen(patn));
+
+       for (a=0; a<strlen(search); ++a) {
+               b=strncasecmp(&search[a],patn,strlen(patn));
                if (b==0) return(b);
-               }
+       }
        return(-1);
 }
 
-void interr(int errnum)        /* display internal error as defined in errmsgs */
-            {
+
+/* display internal error as defined in errmsgs */
+void interr(int errnum) {
        scr_printf("*** INTERNAL ERROR %d\n"
                "(Press any key to continue)\n", errnum);
        inkey();
        logoff(errnum);
 }
 
-
-
 void strproc(char *string)
 {
        int a;
@@ -335,7 +336,7 @@ void strproc(char *string)
        for (a=0; a<strlen(string); ++a) {
                if (string[a]<32) string[a]=32;
                if (string[a]>126) string[a]=32;
-               }
+       }
 
        /* Remove leading and trailing blanks */
        while(string[0]<33) strcpy(string,&string[1]);
@@ -346,8 +347,8 @@ void strproc(char *string)
                if ((string[a]==32)&&(string[a+1]==32)) {
                        strcpy(&string[a],&string[a+1]);
                        a=0;
-                       }
                }
+       }
 
        /* remove characters which would interfere with the network */
        for (a=0; a<strlen(string); ++a) {
@@ -357,10 +358,10 @@ void strproc(char *string)
                if (string[a]==',') strcpy(&string[a],&string[a+1]);
                if (string[a]=='%') strcpy(&string[a],&string[a+1]);
                if (string[a]=='|') strcpy(&string[a],&string[a+1]);
-               }
-
        }
 
+}
+
 
 #ifndef HAVE_STRERROR
 /*
@@ -372,7 +373,7 @@ char *strerror(int e)
 
        snprintf(buf, sizeof buf, "errno = %d",e);
        return(buf);
-       }
+}
 #endif
 
 
@@ -386,10 +387,10 @@ void progress(long int curr, long int cmax)
                scr_printf(".......................................\r");
                scr_flush();
                dots_printed = 0;
-               }
+       }
        else if (curr==cmax) {
                scr_printf("\r%79s\n","");
-               }
+       }
        else {
                a=(curr * 100) / cmax;
                a=a*78; a=a/100;
@@ -397,9 +398,9 @@ void progress(long int curr, long int cmax)
                        scr_printf("*");
                        ++dots_printed;
                        scr_flush();
-                       }
                }
        }
+}
 
 
 /*
@@ -417,27 +418,27 @@ void locate_host(char *hbuf)
        if (who==NULL) {
                strcpy(hbuf,serv_info.serv_fqdn);
                return; 
-               }
+       }
        fgets(buf,sizeof buf,who);
        pclose(who);
 
        b = 0;
        for (a=0; a<strlen(buf); ++a) {
                if ((buf[a]=='(')||(buf[a]==')')) ++b;
-               }
+       }
        if (b<2) {
                strcpy(hbuf,serv_info.serv_fqdn);
                return;
-               }
+       }
 
        for (a=0; a<strlen(buf); ++a) {
                if (buf[a]=='(') {
                        strcpy(buf,&buf[a+1]);
-                       }
                }
+       }
        for (a=0; a<strlen(buf); ++a) {
                if (buf[a]==')') buf[a] = 0;
-               }
+       }
 
        if (strlen(buf)==0) strcpy(hbuf,serv_info.serv_fqdn);
        else strncpy(hbuf,buf,24);
@@ -453,7 +454,7 @@ void locate_host(char *hbuf)
            fail:
                safestrncpy(hbuf, serv_info.serv_fqdn, 24);
                return;
-               }
+       }
 
        if (strncmp(tty, "/dev/", 5))
                goto fail;
@@ -477,11 +478,11 @@ void locate_host(char *hbuf)
 #endif
                        safestrncpy(hbuf, put->ut_line, 24);
 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
-               }
+       }
        else goto fail;
 #endif
 #endif /* HAVE_UTMP_H */
-       }
+}
 
 /*
  * miscellaneous server commands (testing, etc.)
@@ -493,21 +494,21 @@ void misc_server_cmd(char *cmd) {
        serv_gets(buf);
        scr_printf("%s\n",buf);
        if (buf[0]=='1') {
-               set_keepalives(KA_NO);
+               set_keepalives(KA_HALF);
                while (serv_gets(buf), strcmp(buf,"000")) {
                        scr_printf("%s\n",buf);
-                       }
+               }
                set_keepalives(KA_YES);
                return;
-               }
+       }
        if (buf[0]=='4') {
                do {
                        newprompt("> ",buf,255);
                        serv_puts(buf);
-                       } while(strcmp(buf,"000"));
+               } while(strcmp(buf,"000"));
                return;
-               }
        }
+}
 
 
 /*
@@ -527,11 +528,11 @@ int file_checksum(char *filename)
         */
        while (ch=getc(fp), ch>=0) {
                cksum = (cksum + ch);
-               }
+       }
 
        fclose(fp);
        return(cksum);
-       }
+}
 
 /*
  * nuke a directory and its contents
@@ -545,13 +546,14 @@ int nukedir(char *dirname)
        dp = opendir(dirname);
        if (dp == NULL) {
                return(errno);
-               }
+       }
 
        while (d = readdir(dp), d != NULL) {
-               snprintf(filename, sizeof filename, "%s/%s", dirname, d->d_name);
+               snprintf(filename, sizeof filename, "%s/%s",
+                       dirname, d->d_name);
                unlink(filename);
-               }
+       }
 
        closedir(dp);
        return(rmdir(dirname));
-       }
+}
index 02915751c9e2251d998c8574b04399f0872516e7..675a69b814025512f5762ce096e19517e3fcd412 100644 (file)
@@ -61,6 +61,9 @@ void CtdlInternalGetServInfo(struct CtdlServInfo *infobuf) {
                case 10:        infobuf->serv_ok_floors = atoi(buf);
                                break;
                case 11:        infobuf->serv_paging_level = atoi(buf);
+                               break;
+               case 13:        infobuf->serv_supports_qnop = atoi(buf);
+                               break;
                }
            ++a;
            }
index b9f4151db66fd303086feea6afdb654143324a1e..947618326b34888179748813d50389bb29e03fe9 100644 (file)
@@ -552,6 +552,7 @@ parts of the listing:
  Line 13 - The "nonce" for this session, for support of APOP-style
            authentication.  If this field is present, clients may authenticate
            in this manner.
+ Line 14 - Set to nonzero if this server supports the QNOP command.
  
  *** NOTE! ***   The "server type" code is intended to promote global
 compatibility in a scenario in which developers have added proprietary
@@ -1900,6 +1901,19 @@ views.txt for more information on views.  The sole parameter for this command
 is the type of view requested.  VIEW returns OK on success or ERROR on failure.
    
     
+ QNOP   (Quiet No OPeration)
+ This command does nothing, similar to the NOOP command.  However, unlike the
+NOOP command, it returns *absolutely no response* at all.  The client has no
+way of knowing that the command executed.  It is intended for sending
+"keepalives" in situations where a full NOOP would cause the client protocol
+to get out of sync.
+ Naturally, sending this command to a server that doesn't support it is an
+easy way to mess things up.  Therefore, client software should first check
+the output of an INFO command to ensure that the server supports quiet noops.
  ASYN   (ASYNchronous message support)
  
  Negotiate the use of asynchronous, or unsolicited, protocol messages.  The