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 
die(n)21 void die(n) int n; { substdio_flush(subfdout); _exit(n); }
22 
warn(s1,s2)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 
die_nomem()34 void die_nomem() { substdio_puts(subfdout,"fatal: out of memory\n"); die(111); }
die_chdir()35 void die_chdir() { warn("fatal: unable to chdir",""); die(111); }
die_opendir(fn)36 void die_opendir(fn) char *fn; { warn("fatal: unable to opendir ",fn); die(111); }
37 
err(id)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 
fmtstats(s)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 
out(s,n)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 }
outs(s)95 void outs(s) char *s; { out(s,str_len(s)); }
outok(s)96 void outok(s) char *s; { substdio_puts(subfdout,s); }
97 
putstats()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 
main()108 int 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 }
176