From f1b71c9fe7dbb4886588a036399cf5ebe16b7c47 Mon Sep 17 00:00:00 2001
From: Jannis Hoffmann <jannis@fehcom.de>
Date: Tue, 9 Jul 2024 11:44:11 +0200
Subject: removed top level directory

---
 src/qmail-pop3d.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 314 insertions(+)
 create mode 100644 src/qmail-pop3d.c

(limited to 'src/qmail-pop3d.c')

diff --git a/src/qmail-pop3d.c b/src/qmail-pop3d.c
new file mode 100644
index 0000000..ae4b6ea
--- /dev/null
+++ b/src/qmail-pop3d.c
@@ -0,0 +1,314 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "commands.h"
+#include "sig.h"
+#include "getln.h"
+#include "stralloc.h"
+#include "buffer.h"
+#include "alloc.h"
+#include "open.h"
+#include "prioq.h"
+#include "scan.h"
+#include "fmt.h"
+#include "str.h"
+#include "exit.h"
+#include "maildir.h"
+#include "timeout.h"
+#include "qmail.h"
+
+#define FDIN 0
+#define FDOUT 1
+#define POP3_TIMEOUT 1200
+
+int rename(const char *,const char *); // stdio.h
+
+void die() { _exit(0); }
+
+ssize_t saferead(int fd,char *buf,int len)
+{
+  int r;
+  r = timeoutread(POP3_TIMEOUT,fd,buf,len);
+  if (r <= 0) die();
+  return r;
+}
+
+ssize_t safewrite(int fd,char *buf,int len)
+{
+  int r;
+  r = timeoutwrite(POP3_TIMEOUT,fd,buf,len);
+  if (r <= 0) die();
+  return r;
+}
+
+char inbuf[BUFSIZE_LINE];
+buffer bi = BUFFER_INIT(saferead,FDIN,inbuf,sizeof(inbuf));
+char outbuf[BUFSIZE_LINE];
+buffer bo = BUFFER_INIT(safewrite,FDOUT,outbuf,sizeof(outbuf));
+
+void out(char *buf,int len)
+{
+  buffer_put(&bo,buf,len);
+}
+void outs(char *s)
+{
+  buffer_puts(&bo,s);
+}
+void flush()
+{
+  buffer_flush(&bo);
+}
+void err(char *s)
+{
+  outs("-ERR ");
+  outs(s);
+  outs("\r\n");
+  flush();
+}
+
+void die_nomem() { err("out of memory"); die(); }
+void die_nomaildir() { err("this user has no $HOME/Maildir"); die(); }
+void die_scan() { err("unable to scan $HOME/Maildir"); die(); }
+
+void err_syntax() { err("syntax error"); }
+void err_unimpl() { err("unimplemented"); }
+void err_deleted() { err("already deleted"); }
+void err_nozero() { err("messages are counted from 1"); }
+void err_toobig() { err("not that many messages"); }
+void err_nosuch() { err("unable to open that message"); }
+void err_nounlink() { err("unable to unlink all deleted messages"); }
+
+void okay() { outs("+OK \r\n"); flush(); }
+
+void printfn(char *fn)
+{
+  fn += 4;
+  out(fn,str_chr(fn,':'));
+}
+
+char strnum[FMT_ULONG];
+stralloc line = {0};
+
+void blast(buffer *bf,unsigned long limit)
+{
+  int match;
+  int inheaders = 1;
+ 
+  for (;;) {
+    if (getln(bf,&line,&match,'\n') != 0) die();
+    if (!match && !line.len) break;
+    if (match) --line.len; /* no way to pass this info over POP */
+    if (limit) if (!inheaders) if (!--limit) break;
+    if (!line.len)
+      inheaders = 0;
+    else
+      if (line.s[0] == '.')
+        out(".",1);
+    out(line.s,line.len);
+    out("\r\n",2);
+    
+    if (!match) break;
+  }
+  out("\r\n.\r\n",5);
+  flush();
+}
+
+stralloc filenames = {0};
+prioq pq = {0};
+
+struct message {
+  int flagdeleted;
+  unsigned long size;
+  char *fn;
+} *m;
+
+int numm;
+int last = 0;
+
+void getlist()
+{
+  struct prioq_elt pe;
+  struct stat st;
+  int i;
+ 
+  maildir_clean(&line);
+  if (maildir_scan(&pq,&filenames,1,1) == -1) die_scan();
+ 
+  numm = pq.p ? pq.len : 0;
+  m = (struct message *) alloc(numm * sizeof(struct message));
+  if (!m) die_nomem();
+ 
+  for (i = 0; i < numm; ++i) {
+    if (!prioq_min(&pq,&pe)) { numm = i; break; }
+    prioq_delmin(&pq);
+    m[i].fn = filenames.s + pe.id;
+    m[i].flagdeleted = 0;
+    if (stat(m[i].fn,&st) == -1)
+      m[i].size = 0;
+    else
+      m[i].size = st.st_size;
+  }
+}
+
+void pop3_stat()
+{
+  int i;
+  unsigned long total;
+ 
+  total = 0;
+  for (i = 0; i < numm; ++i) 
+    if (!m[i].flagdeleted) total += m[i].size;
+
+  outs("+OK ");
+  out(strnum,fmt_uint(strnum,numm));
+  outs(" ");
+  out(strnum,fmt_ulong(strnum,total));
+  outs("\r\n");
+  flush();
+}
+
+void pop3_rset()
+{
+  int i;
+
+  for (i = 0; i < numm; ++i) 
+    m[i].flagdeleted = 0;
+  last = 0;
+  okay();
+}
+
+void pop3_last()
+{
+  outs("+OK ");
+  out(strnum,fmt_uint(strnum,last));
+  outs("\r\n");
+  flush();
+}
+
+void pop3_quit()
+{
+  int i;
+
+  for (i = 0; i < numm; ++i)
+    if (m[i].flagdeleted) {
+      if (unlink(m[i].fn) == -1) err_nounlink();
+    } else {
+      if (str_start(m[i].fn,"new/")) {
+        if (!stralloc_copys(&line,"cur/")) die_nomem();
+        if (!stralloc_cats(&line,m[i].fn + 4)) die_nomem();
+        if (!stralloc_cats(&line,":2,")) die_nomem();
+        if (!stralloc_0(&line)) die_nomem();
+        rename(m[i].fn,line.s); /* if it fails, bummer */
+      }
+    }
+  okay();
+  die();
+}
+
+int msgno(char *arg)
+{
+  unsigned long u;
+
+  if (!scan_ulong(arg,&u)) { err_syntax(); return -1; }
+  if (!u) { err_nozero(); return -1; }
+  --u;
+  if (u >= numm) { err_toobig(); return -1; }
+  if (m[u].flagdeleted) { err_deleted(); return -1; }
+  return u;
+}
+
+void pop3_dele(char *arg)
+{
+  int i;
+
+  i = msgno(arg);
+  if (i == -1) return;
+  m[i].flagdeleted = 1;
+  if (i + 1 > last) last = i + 1;
+  okay();
+}
+
+void list(int i,int flaguidl)
+{
+  out(strnum,fmt_uint(strnum,i + 1));
+  outs(" ");
+  if (flaguidl) printfn(m[i].fn);
+  else out(strnum,fmt_ulong(strnum,m[i].size));
+  outs("\r\n");
+}
+
+void dolisting(char *arg,int flaguidl)
+{
+  unsigned int i;
+
+  if (*arg) {
+    i = msgno(arg);
+    if (i == -1) return;
+
+    outs("+OK ");
+    list(i,flaguidl);
+  } else {
+    okay();
+    for (i = 0; i < numm; ++i)
+      if (!m[i].flagdeleted) list(i,flaguidl);
+    outs(".\r\n");
+  }
+  flush();
+}
+
+void pop3_uidl(char *arg) { dolisting(arg,1); }
+void pop3_list(char *arg) { dolisting(arg,0); }
+
+char msgbuf[BUFSIZE_MESS];
+buffer bm; 
+
+void pop3_top(char *arg)
+{
+  int i;
+  unsigned long limit;
+  int fd;
+ 
+  i = msgno(arg);
+  if (i == -1) return;
+ 
+  arg += scan_ulong(arg,&limit);
+  while (*arg == ' ') ++arg;
+  if (scan_ulong(arg,&limit)) ++limit; 
+  else limit = 0;
+ 
+  fd = open_read(m[i].fn);
+  if (fd == -1) { err_nosuch(); return; }
+  okay();
+  buffer_init(&bm,read,fd,msgbuf,sizeof(msgbuf));
+  blast(&bm,limit);
+  close(fd);
+}
+
+struct commands pop3commands[] = {
+  { "quit", pop3_quit, 0 }
+, { "stat", pop3_stat, 0 }
+, { "list", pop3_list, 0 }
+, { "uidl", pop3_uidl, 0 }
+, { "dele", pop3_dele, 0 }
+, { "retr", pop3_top, 0 }
+, { "rset", pop3_rset, 0 }
+, { "last", pop3_last, 0 }
+, { "top", pop3_top, 0 }
+, { "noop", okay, 0 }
+, { 0, err_unimpl, 0 }
+} ;
+
+int main(int argc,char **argv)
+{
+  sig_alarmcatch(die);
+  sig_pipeignore();
+ 
+  if (!argv[1]) die_nomaildir();
+  if (chdir(argv[1]) == -1) die_nomaildir();
+ 
+  getlist();
+
+  okay();
+  commands(&bi,pop3commands);
+  die();
+}
-- 
cgit v1.2.3