chiark / gitweb /
Merge branches 'idx/verh' and 'idx/qmqpc'
[qmail] / qmail-qread.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include "stralloc.h"
4 #include "substdio.h"
5 #include "subfd.h"
6 #include "fmt.h"
7 #include "str.h"
8 #include "getln.h"
9 #include "fmtqfn.h"
10 #include "readsubdir.h"
11 #include "auto_qmail.h"
12 #include "open.h"
13 #include "datetime.h"
14 #include "date822fmt.h"
15 #include "readwrite.h"
16 #include "error.h"
17 #include "exit.h"
18
19 readsubdir rs;
20
21 void die(n) int n; { substdio_flush(subfdout); _exit(n); }
22
23 void warn(s1,s2) char *s1; char *s2;
24 {
25  char *x;
26  x = error_str(errno);
27  substdio_puts(subfdout,s1);
28  substdio_puts(subfdout,s2);
29  substdio_puts(subfdout,": ");
30  substdio_puts(subfdout,x);
31  substdio_puts(subfdout,"\n");
32 }
33
34 void die_nomem() { substdio_puts(subfdout,"fatal: out of memory\n"); die(111); }
35 void die_chdir() { warn("fatal: unable to chdir",""); die(111); }
36 void die_opendir(fn) char *fn; { warn("fatal: unable to opendir ",fn); die(111); }
37
38 void err(id) unsigned long id;
39 {
40  char foo[FMT_ULONG];
41  foo[fmt_ulong(foo,id)] = 0;
42  warn("warning: trouble with #",foo);
43 }
44
45 char fnmess[FMTQFN];
46 char fninfo[FMTQFN];
47 char fnlocal[FMTQFN];
48 char fnremote[FMTQFN];
49 char fnbounce[FMTQFN];
50
51 char inbuf[1024];
52 stralloc sender = {0};
53
54 unsigned long id;
55 datetime_sec qtime;
56 int flagbounce;
57 unsigned long size;
58
59 unsigned int fmtstats(s)
60 char *s;
61 {
62  struct datetime dt;
63  unsigned int len;
64  unsigned int i;
65
66  len = 0;
67  datetime_tai(&dt,qtime);
68  i = date822fmt(s,&dt) - 7/*XXX*/; len += i; if (s) s += i;
69  i = fmt_str(s," GMT  #"); len += i; if (s) s += i;
70  i = fmt_ulong(s,id); len += i; if (s) s += i;
71  i = fmt_str(s,"  "); len += i; if (s) s += i;
72  i = fmt_ulong(s,size); len += i; if (s) s += i;
73  i = fmt_str(s,"  <"); len += i; if (s) s += i;
74  i = fmt_str(s,sender.s + 1); len += i; if (s) s += i;
75  i = fmt_str(s,"> "); len += i; if (s) s += i;
76  if (flagbounce)
77   {
78    i = fmt_str(s," bouncing"); len += i; if (s) s += i;
79   }
80
81  return len;
82 }
83
84 stralloc stats = {0};
85
86 void out(s,n) char *s; unsigned int n;
87 {
88  while (n > 0)
89   {
90    substdio_put(subfdout,((*s >= 32) && (*s <= 126)) ? s : "_",1);
91    --n;
92    ++s;
93   }
94 }
95 void outs(s) char *s; { out(s,str_len(s)); }
96 void outok(s) char *s; { substdio_puts(subfdout,s); }
97
98 void putstats()
99 {
100  if (!stralloc_ready(&stats,fmtstats(FMT_LEN))) die_nomem();
101  stats.len = fmtstats(stats.s);
102  out(stats.s,stats.len);
103  outok("\n");
104 }
105
106 stralloc line = {0};
107
108 void main()
109 {
110  int channel;
111  int match;
112  struct stat st;
113  int fd;
114  substdio ss;
115  int x;
116
117  if (chdir(auto_qmail) == -1) die_chdir();
118  if (chdir("queue") == -1) die_chdir();
119  readsubdir_init(&rs,"info",die_opendir);
120
121  while (x = readsubdir_next(&rs,&id))
122    if (x > 0)
123     {
124      fmtqfn(fnmess,"mess/",id,1);
125      fmtqfn(fninfo,"info/",id,1);
126      fmtqfn(fnlocal,"local/",id,1);
127      fmtqfn(fnremote,"remote/",id,1);
128      fmtqfn(fnbounce,"bounce/",id,0);
129
130      if (stat(fnmess,&st) == -1) { err(id); continue; }
131      size = st.st_size;
132      flagbounce = !stat(fnbounce,&st);
133
134      fd = open_read(fninfo);
135      if (fd == -1) { err(id); continue; }
136      substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf));
137      if (getln(&ss,&sender,&match,0) == -1) die_nomem();
138      if (fstat(fd,&st) == -1) { close(fd); err(id); continue; }
139      close(fd);
140      qtime = st.st_mtime;
141
142      putstats();
143
144      for (channel = 0;channel < 2;++channel)
145       {
146        fd = open_read(channel ? fnremote : fnlocal);
147        if (fd == -1)
148         {
149          if (errno != error_noent)
150            err(id);
151         }
152        else
153         {
154          for (;;)
155           {
156            if (getln(&ss,&line,&match,0) == -1) die_nomem();
157            if (!match) break;
158            switch(line.s[0])
159             {
160              case 'D':
161                outok("  done");
162              case 'T':
163                outok(channel ? "\tremote\t" : "\tlocal\t");
164                outs(line.s + 1);
165                outok("\n");
166                break;
167             }
168           }
169          close(fd);
170         }
171       }
172     }
173
174  die(0);
175 }