Skeleton nntp_xover() checked in. It seems that some clients make use of the XOVER...
[citadel.git] / citadel / modules / nntp / serv_nntp.c
index 2d1a2c52e75fea6ab815678ebe926b272c0b7e3a..26b0ccd4f9a7bc55e22846353e7d0800d15a4fba 100644 (file)
@@ -531,6 +531,25 @@ void nntp_help(void) {
 }
 
 
+//
+// Implement DATE command.
+//
+void nntp_date(void) {
+       time_t now;
+       struct tm nowLocal;
+       struct tm nowUtc;
+       char tsFromUtc[32];
+
+       now = time(NULL);
+       localtime_r(&now, &nowLocal);
+       gmtime_r(&now, &nowUtc);
+
+       strftime(tsFromUtc, sizeof(tsFromUtc), "%Y%m%d%H%M%S", &nowUtc);
+
+       cprintf("111 %s\r\n", tsFromUtc);
+}
+
+
 //
 // back end for the LISTGROUP command , called for each message number
 //
@@ -790,6 +809,33 @@ void nntp_article(const char *cmd) {
 }
 
 
+//
+// Utility function for nntp_last_next() that turns a msgnum into a message ID.
+// The memory for the returned string is pwnz0red by the caller.
+//
+char *message_id_from_msgnum(long msgnum) {
+
+       char *fetched_message_id = NULL;
+       CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
+       CtdlOutputMsg(msgnum,
+                       MT_RFC822,              // output in RFC822 format ... sort of
+                       HEADERS_FAST,           // headers, body, or both?
+                       0,                      // don't do Citadel protocol responses
+                       1,                      // CRLF newlines
+                       NULL,                   // teh whole thing, not just a section
+                       0,                      // no flags yet ... maybe new ones for Path: etc ?
+                       NULL,
+                       NULL,
+                       &fetched_message_id     // extract the message ID from the message as we go...
+       );
+       StrBuf *msgtext = CC->redirect_buffer;
+       CC->redirect_buffer = NULL;
+
+       FreeStrBuf(&msgtext);
+       return(fetched_message_id);
+}
+
+
 //
 // The LAST and NEXT commands are so similar that they are handled by a single function.
 //
@@ -822,22 +868,87 @@ void nntp_last_next(const char *cmd) {
 
        // ok, here we go ... fetch the msglist so we can figure out our place in the universe
        struct nntp_msglist nm;
-       long low_water_mark = 0;
-       long high_water_mark = 0;
+       int i = 0;
+       long selected_msgnum = 0;
+       char *message_id = NULL;
 
        nm = nntp_fetch_msglist(&CC->room);
-       if ((nm.num_msgs > 0) && (nm.msgnums != NULL)) {
-               low_water_mark = nm.msgnums[0];
-               high_water_mark = nm.msgnums[nm.num_msgs - 1];
-       }
-       else {
+       if ((nm.num_msgs < 0) || (nm.msgnums == NULL)) {
                cprintf("500 something bad happened\r\n");
                return;
        }
 
-       // ok now let's get all up in this msglist FIXME
+       if ( (acmd == NNTP_LAST) && (nm.num_msgs == 0) ) {
+                       cprintf("422 no previous article in this group\r\n");   // nothing here
+       }
+
+       else if ( (acmd == NNTP_LAST) && (nntpstate->current_article_number <= nm.msgnums[0]) ) {
+                       cprintf("422 no previous article in this group\r\n");   // already at the beginning
+       }
+
+       else if (acmd == NNTP_LAST) {
+               for (i=0; ((i<nm.num_msgs)&&(selected_msgnum<=0)); ++i) {
+                       if ( (nm.msgnums[i] >= nntpstate->current_article_number) && (i > 0) ) {
+                               selected_msgnum = nm.msgnums[i-1];
+                       }
+               }
+               if (selected_msgnum > 0) {
+                       nntpstate->current_article_number = selected_msgnum;
+                       message_id = message_id_from_msgnum(nntpstate->current_article_number);
+                       cprintf("223 %ld <%s>\r\n", nntpstate->current_article_number, message_id);
+                       if (message_id) free(message_id);
+               }
+               else {
+                       cprintf("422 no previous article in this group\r\n");
+               }
+       }
+
+       else if ( (acmd == NNTP_NEXT) && (nm.num_msgs == 0) ) {
+                       cprintf("421 no next article in this group\r\n");       // nothing here
+       }
 
-       cprintf("500 FIXME cmd=%d current_article_number=%ld\r\n", acmd, nntpstate->current_article_number);
+       else if ( (acmd == NNTP_NEXT) && (nntpstate->current_article_number >= nm.msgnums[nm.num_msgs-1]) ) {
+                       cprintf("421 no next article in this group\r\n");       // already at the end
+       }
+
+       else if (acmd == NNTP_NEXT) {
+               for (i=0; ((i<nm.num_msgs)&&(selected_msgnum<=0)); ++i) {
+                       if (nm.msgnums[i] > nntpstate->current_article_number) {
+                               selected_msgnum = nm.msgnums[i];
+                       }
+               }
+               if (selected_msgnum > 0) {
+                       nntpstate->current_article_number = selected_msgnum;
+                       message_id = message_id_from_msgnum(nntpstate->current_article_number);
+                       cprintf("223 %ld <%s>\r\n", nntpstate->current_article_number, message_id);
+                       if (message_id) free(message_id);
+               }
+               else {
+                       cprintf("421 no next article in this group\r\n");
+               }
+       }
+
+       // should never get here
+       else {
+               cprintf("500 internal error\r\n");
+       }
+
+       if (nm.msgnums != NULL) {
+               free(nm.msgnums);
+       }
+
+}
+
+
+//
+// XOVER is used by some clients, even if we don't offer it
+//
+void nntp_xover(const char *cmd) {
+       if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
+
+       // citnntp *nntpstate = (citnntp *) CC->session_specific_data;
+
+       cprintf("500 not implemented yet FIXME\r\n");
 }
 
 
@@ -869,6 +980,10 @@ void nntp_command_loop(void)
                nntp_help();
        }
 
+       else if (!strcasecmp(cmdname, "date")) {
+               nntp_date();
+       }
+
        else if (!strcasecmp(cmdname, "capabilities")) {
                nntp_capabilities();
        }
@@ -919,6 +1034,10 @@ void nntp_command_loop(void)
                nntp_last_next(ChrPtr(Cmd));
        }
 
+       else if (!strcasecmp(cmdname, "xover")) {
+               nntp_xover(ChrPtr(Cmd));
+       }
+
        else {
                cprintf("500 I'm afraid I can't do that.\r\n");
        }