]> diplodocus.org Git - nmh/blobdiff - test/fakepop.c
Alter HasSuffixC()'s char * to be const.
[nmh] / test / fakepop.c
index bca565d14b80e3ca6ba131ef6a7f6837e08093cf..bc2baae0c399e32f01e4dd1766d36a882db1992d 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <netdb.h>
 #include <errno.h>
 #include <errno.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
 #include <sys/types.h>
 #include <sys/types.h>
-#include <sys/select.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
 #include <limits.h>
 #include <limits.h>
-#include <signal.h>
 
 #define PIDFILE "/tmp/fakepop.pid"
 #define LINESIZE 1024
 #define BUFALLOC 4096
 
 #define CHECKUSER()    if (!user) { \
 
 #define PIDFILE "/tmp/fakepop.pid"
 #define LINESIZE 1024
 #define BUFALLOC 4096
 
 #define CHECKUSER()    if (!user) { \
-                               putpop(s, "-ERR Aren't you forgetting " \
+                               putcrlf(s, "-ERR Aren't you forgetting " \
                                       "something?  Like the USER command?"); \
                                continue; \
                        }
                                       "something?  Like the USER command?"); \
                                continue; \
                        }
-#define CHECKUSERPASS()        CHECKUSER() \
-                       if (! pass) { \
-                               putpop(s, "-ERR Um, hello?  Forget to " \
+#define CHECKAUTH()    if (!auth) { \
+                               putcrlf(s, "-ERR Um, hello?  Forget to " \
                                       "log in?"); \
                                continue; \
                        }
 
                                       "log in?"); \
                                continue; \
                        }
 
-static void killpidfile(void);
-static void handleterm(int);
-static void putpop(int, char *);
+void putcrlf(int, char *);
+int serve(const char *, const char *);
+
 static void putpopbulk(int, char *);
 static int getpop(int, char *, ssize_t);
 static char *readmessage(FILE *);
 static void putpopbulk(int, char *);
 static int getpop(int, char *, ssize_t);
 static char *readmessage(FILE *);
@@ -47,187 +39,73 @@ static char *readmessage(FILE *);
 int
 main(int argc, char *argv[])
 {
 int
 main(int argc, char *argv[])
 {
-       struct addrinfo hints, *res;
-       struct stat st;
-       FILE *f, *pid;
+       FILE **mfiles;
        char line[LINESIZE];
        char line[LINESIZE];
-       fd_set readfd;
-       struct timeval tv;
-       pid_t child;
-       int octets = 0, rc, l, s, on, user = 0, pass = 0, deleted = 0;
-
-       if (argc != 5) {
-               fprintf(stderr, "Usage: %s mail-file port username "
-                       "password\n", argv[0]);
-               exit(1);
-       }
-
-       if (!(f = fopen(argv[1], "r"))) {
-               fprintf(stderr, "Unable to open message file \"%s\": %s\n",
-                       argv[1], strerror(errno));
+       int rc, s, user = 0, auth = 0, i, j;
+       int numfiles;
+       size_t *octets;
+       const char *xoauth;
+
+       if (argc < 5) {
+               fprintf(stderr, "Usage: %s port username "
+                       "password mail-file [mail-file ...]\n", argv[0]);
                exit(1);
        }
 
                exit(1);
        }
 
-       /*
-        * POP wants the size of the maildrop in bytes, but with \r\n line
-        * endings.  Calculate that.
-        */
-
-       while (fgets(line, sizeof(line), f)) {
-               octets += strlen(line);
-               if (strrchr(line, '\n'))
-                       octets++;
-       }
-
-       rewind(f);
-
-       /*
-        * If there is a pid file around, kill the previously running
-        * fakepop process.
-        */
-
-       if (stat(PIDFILE, &st) == 0) {
-               long oldpid;
-
-               if (!(pid = fopen(PIDFILE, "r"))) {
-                       fprintf(stderr, "Cannot open " PIDFILE
-                               " (%s), continuing ...\n", strerror(errno));
-               } else {
-                       rc = fscanf(pid, "%ld", &oldpid);
-                       fclose(pid);
-
-                       if (rc != 1) {
-                               fprintf(stderr, "Unable to parse pid in "
-                                       PIDFILE ", continuing ...\n");
-                       } else {
-                               kill((pid_t) oldpid, SIGTERM);
-                       }
-               }
-
-               unlink(PIDFILE);
+       if (strcmp(argv[2], "XOAUTH") == 0) {
+               xoauth = argv[3];
+       } else {
+               xoauth = NULL;
        }
 
        }
 
-       memset(&hints, 0, sizeof(hints));
-
-       hints.ai_family = PF_INET;
-       hints.ai_socktype = SOCK_STREAM;
-       hints.ai_protocol = IPPROTO_TCP;
-       hints.ai_flags = AI_PASSIVE;
-
-       rc = getaddrinfo("127.0.0.1", argv[2], &hints, &res);
-
-       if (rc) {
-               fprintf(stderr, "Unable to resolve localhost/%s: %s\n",
-                       argv[2], gai_strerror(rc));
-               exit(1);
-       }
+       numfiles = argc - 4;
 
 
-       l = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+       mfiles = malloc(sizeof(FILE *) * numfiles);
 
 
-       if (l == -1) {
-               fprintf(stderr, "Unable to create listening socket: %s\n",
-                       strerror(errno));
+       if (! mfiles) {
+               fprintf(stderr, "Unable to allocate %d bytes for file "
+                       "array\n", (int) (sizeof(FILE *) * numfiles));
                exit(1);
        }
 
                exit(1);
        }
 
-       on = 1;
+       octets = malloc(sizeof(*octets) * numfiles);
 
 
-       if (setsockopt(l, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
-               fprintf(stderr, "Unable to set SO_REUSEADDR: %s\n",
-                       strerror(errno));
+       if (! octets) {
+               fprintf(stderr, "Unable to allocate %d bytes for size "
+                       "array\n", (int) (sizeof(FILE *) * numfiles));
                exit(1);
        }
 
                exit(1);
        }
 
-       if (bind(l, res->ai_addr, res->ai_addrlen) == -1) {
-               fprintf(stderr, "Unable to bind socket: %s\n", strerror(errno));
-               exit(1);
-       }
-
-       if (listen(l, 1) == -1) {
-               fprintf(stderr, "Unable to listen on socket: %s\n",
-                       strerror(errno));
-               exit(1);
-       }
-
-       /*
-        * Fork off a copy of ourselves, print out our child pid, then
-        * exit.
-        */
+       for (i = 4, j = 0; i < argc; i++, j++) {
+               if (!(mfiles[j] = fopen(argv[i], "r"))) {
+                       fprintf(stderr, "Unable to open message file \"%s\""
+                               ": %s\n", argv[i], strerror(errno));
+                       exit(1);
+               }
 
 
-       switch (child = fork()) {
-       case -1:
-               fprintf(stderr, "Unable to fork child: %s\n", strerror(errno));
-               exit(1);
-               break;
-       case 0:
                /*
                /*
-                * Close stdin and stdout so $() in the shell will get an
-                * EOF.  For now leave stderr open.
+                * POP wants the size of the maildrop in bytes, but
+                * with \r\n line endings.  Calculate that.
                 */
                 */
-               fclose(stdin);
-               fclose(stdout);
-               break;
-       default:
-               printf("%ld\n", (long) child);
-               exit(0);
-       }
-
-       /*
-        * Now that our socket and files are set up, wait 30 seconds for
-        * a connection.  If there isn't one, then exit.
-        */
-
-       if (!(pid = fopen(PIDFILE, "w"))) {
-               fprintf(stderr, "Cannot open " PIDFILE ": %s\n",
-                       strerror(errno));
-               exit(1);
-       }
-
-       fprintf(pid, "%ld\n", (long) getpid());
-       fclose(pid);
-
-       signal(SIGTERM, handleterm);
-       atexit(killpidfile);
-
-       FD_ZERO(&readfd);
-       FD_SET(l, &readfd);
-
-       tv.tv_sec = 30;
-       tv.tv_usec = 0;
-
-       rc = select(l + 1, &readfd, NULL, NULL, &tv);
-
-       if (rc < 0) {
-               fprintf(stderr, "select() failed: %s\n", strerror(errno));
-               exit(1);
-       }
 
 
-       /*
-        * If we get a timeout, just silently exit
-        */
+               octets[j] = 0;
 
 
-       if (rc == 0) {
-               exit(1);
-       }
-
-       /*
-        * We got a connection; accept it.  Right after that close our
-        * listening socket so we won't get any more connections on it.
-        */
+               while (fgets(line, sizeof(line), mfiles[j])) {
+                       octets[j] += strlen(line);
+                       if (strrchr(line, '\n'))
+                               octets[j]++;
+               }
 
 
-       if ((s = accept(l, NULL, NULL)) == -1) {
-               fprintf(stderr, "Unable to accept connection: %s\n",
-                       strerror(errno));
-               exit(1);
+               rewind(mfiles[j]);
        }
 
        }
 
-       close(l);
+       s = serve(PIDFILE, argv[1]);
 
        /*
         * Pretend to be a POP server
         */
 
 
        /*
         * Pretend to be a POP server
         */
 
-       putpop(s, "+OK Not really a POP server, but we play one on TV");
+       putcrlf(s, "+OK Not really a POP server, but we play one on TV");
 
        for (;;) {
                char linebuf[LINESIZE];
 
        for (;;) {
                char linebuf[LINESIZE];
@@ -239,86 +117,103 @@ main(int argc, char *argv[])
 
                if (strcasecmp(linebuf, "CAPA") == 0) {
                        putpopbulk(s, "+OK We have no capabilities, really\r\n"
 
                if (strcasecmp(linebuf, "CAPA") == 0) {
                        putpopbulk(s, "+OK We have no capabilities, really\r\n"
-                                  "FAKE-CAPABILITY\r\n.\r\n");
+                                  "FAKE-CAPABILITY\r\n");
+                       if (xoauth != NULL) {
+                               putcrlf(s, "SASL XOAUTH2");
+                       }
+                       putcrlf(s, ".");
                } else if (strncasecmp(linebuf, "USER ", 5) == 0) {
                } else if (strncasecmp(linebuf, "USER ", 5) == 0) {
-                       if (strcmp(linebuf + 5, argv[3]) == 0) {
-                               putpop(s, "+OK Niiiice!");
+                       if (strcmp(linebuf + 5, argv[2]) == 0) {
+                               putcrlf(s, "+OK Niiiice!");
                                user = 1;
                        } else {
                                user = 1;
                        } else {
-                               putpop(s, "-ERR Don't play me, bro!");
+                               putcrlf(s, "-ERR Don't play me, bro!");
                        }
                } else if (strncasecmp(linebuf, "PASS ", 5) == 0) {
                        CHECKUSER();
                        }
                } else if (strncasecmp(linebuf, "PASS ", 5) == 0) {
                        CHECKUSER();
-                       if (strcmp(linebuf + 5, argv[4]) == 0) {
-                               putpop(s, "+OK Aren't you a sight "
+                       if (strcmp(linebuf + 5, argv[3]) == 0) {
+                               putcrlf(s, "+OK Aren't you a sight "
                                       "for sore eyes!");
                                       "for sore eyes!");
-                               pass = 1;
+                               auth = 1;
                        } else {
                        } else {
-                               putpop(s, "-ERR C'mon!");
+                               putcrlf(s, "-ERR C'mon!");
                        }
                        }
+               } else if (xoauth != NULL
+                          && strncasecmp(linebuf, "AUTH XOAUTH2", 12) == 0) {
+                       if (strstr(linebuf, xoauth) == NULL) {
+                               putcrlf(s, "+ base64-json-err");
+                               rc = getpop(s, linebuf, sizeof(linebuf));
+                               if (rc != 0)
+                                       break;  /* Error or EOF */
+                               putcrlf(s, "-ERR [AUTH] Invalid credentials.");
+                               continue;
+                       }
+                       putcrlf(s, "+OK Welcome.");
+                       auth = 1;
                } else if (strcasecmp(linebuf, "STAT") == 0) {
                } else if (strcasecmp(linebuf, "STAT") == 0) {
-                       CHECKUSERPASS();
-                       if (deleted) {
-                               strncpy(linebuf, "+OK 0 0", sizeof(linebuf));
-                       } else {
-                               snprintf(linebuf, sizeof(linebuf),
-                                        "+OK 1 %d", octets);
+                       size_t total = 0;
+                       CHECKAUTH();
+                       for (i = 0, j = 0; i < numfiles; i++) {
+                               if (mfiles[i]) {
+                                       total += octets[i];
+                                       j++;
+                               }
                        }
                        }
-                       putpop(s, linebuf);
-               } else if (strcasecmp(linebuf, "RETR 1") == 0) {
-                       CHECKUSERPASS();
-                       if (deleted) {
-                               putpop(s, "-ERR Sorry, don't have it anymore");
+                       snprintf(linebuf, sizeof(linebuf),
+                                        "+OK %d %d", i, (int) total);
+                       putcrlf(s, linebuf);
+               } else if (strncasecmp(linebuf, "RETR ", 5) == 0) {
+                       CHECKAUTH();
+                       rc = sscanf(linebuf + 5, "%d", &i);
+                       if (rc != 1) {
+                               putcrlf(s, "-ERR Whaaaa...?");
+                               continue;
+                       }
+                       if (i < 1 || i > numfiles) {
+                               putcrlf(s, "-ERR That message number is "
+                                      "out of range, jerkface!");
+                               continue;
+                       }
+                       if (mfiles[i - 1] == NULL) {
+                               putcrlf(s, "-ERR Sorry, don't have it anymore");
                        } else {
                        } else {
-                               char *buf = readmessage(f);
-                               putpop(s, "+OK Here you go ...");
+                               char *buf = readmessage(mfiles[i - 1]);
+                               putcrlf(s, "+OK Here you go ...");
                                putpopbulk(s, buf);
                                free(buf);
                        }
                                putpopbulk(s, buf);
                                free(buf);
                        }
-               } else if (strncasecmp(linebuf, "RETR ", 5) == 0) {
-                       CHECKUSERPASS();
-                       putpop(s, "-ERR Sorry man, out of range!");
-               } else if (strcasecmp(linebuf, "DELE 1") == 0) {
-                       CHECKUSERPASS();
-                       if (deleted) {
-                               putpop(s, "-ERR Um, didn't you tell me "
+               } else if (strncasecmp(linebuf, "DELE ", 5) == 0) {
+                       CHECKAUTH();
+                       rc = sscanf(linebuf + 5, "%d", &i);
+                       if (rc != 1) {
+                               putcrlf(s, "-ERR Whaaaa...?");
+                               continue;
+                       }
+                       if (i < 1 || i > numfiles) {
+                               putcrlf(s, "-ERR That message number is "
+                                      "out of range, jerkface!");
+                               continue;
+                       }
+                       if (mfiles[i - 1] == NULL) {
+                               putcrlf(s, "-ERR Um, didn't you tell me "
                                       "to delete it already?");
                        } else {
                                       "to delete it already?");
                        } else {
-                               putpop(s, "+OK Alright man, I got rid of it");
-                               deleted = 1;
+                               fclose(mfiles[i - 1]);
+                               mfiles[i - 1] = NULL;
+                               putcrlf(s, "+OK Alright man, I got rid of it");
                        }
                        }
-               } else if (strncasecmp(linebuf, "DELE ", 5) == 0) {
-                       CHECKUSERPASS();
-                       putpop(s, "-ERR Sorry man, out of range!");
                } else if (strcasecmp(linebuf, "QUIT") == 0) {
                } else if (strcasecmp(linebuf, "QUIT") == 0) {
-                       putpop(s, "+OK See ya, wouldn't want to be ya!");
+                       putcrlf(s, "+OK See ya, wouldn't want to be ya!");
                        close(s);
                        break;
                } else {
                        close(s);
                        break;
                } else {
-                       putpop(s, "-ERR Um, what?");
+                       putcrlf(s, "-ERR Um, what?");
                }
        }
 
        exit(0);
 }
 
                }
        }
 
        exit(0);
 }
 
-/*
- * Send one line to the POP client
- */
-
-static void
-putpop(int socket, char *data)
-{
-       struct iovec iov[2];
-
-       iov[0].iov_base = data;
-       iov[0].iov_len = strlen(data);
-       iov[1].iov_base = "\r\n";
-       iov[1].iov_len = 2;
-
-       writev(socket, iov, 2);
-}
-
 /*
  * Put one big buffer to the POP server.  Should have already had the line
  * endings set up and dot-stuffed if necessary.
 /*
  * Put one big buffer to the POP server.  Should have already had the line
  * endings set up and dot-stuffed if necessary.
@@ -329,7 +224,9 @@ putpopbulk(int socket, char *data)
 {
        ssize_t datalen = strlen(data);
 
 {
        ssize_t datalen = strlen(data);
 
-       write(socket, data, datalen);
+       if (write(socket, data, datalen) < 0) {
+           perror ("write");
+       }
 }
 
 /*
 }
 
 /*
@@ -416,29 +313,7 @@ readmessage(FILE *file)
 
        strcat(buffer, ".\r\n");
 
 
        strcat(buffer, ".\r\n");
 
-       return buffer;
-}
+       rewind(file);
 
 
-/*
- * Handle a SIGTERM
- */
-
-static void
-handleterm(int signal)
-{
-       (void) signal;
-
-       killpidfile();
-       fflush(NULL);
-       _exit(1);
-}
-
-/*
- * Get rid of our pid file
- */
-
-static void
-killpidfile(void)
-{
-       unlink(PIDFILE);
+       return buffer;
 }
 }