TaskEstimate now uses the FogBugz object stuff. Wow, is the code ever
[wvapps.git] / retchmail / retchmail.cc
blob6c8c1a50a61e777ef70a1ec8177cf21d1b64ee71
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2003 Net Integration Technologies, Inc.
5 * Avery's insanely fast alternative to Fetchmail
7 * This code is LGPL - see the file COPYING.LIB for a full copy of the
8 * license.
9 */
11 // WvStreams headers
12 #include "strutils.h"
13 #include "uniconfroot.h"
14 #include "wvlockfile.h"
15 #include "wvver.h"
16 #include "wvtcp.h"
17 #include "wvlog.h"
18 #include "wvpipe.h"
19 #include "wvistreamlist.h"
20 #include "wvlogrcv.h"
21 #include "wvsslstream.h"
22 #include "wvhashtable.h"
23 #include "wvcrash.h"
24 #include "wvhex.h"
26 // Retchmail headers
27 #include "wvsendmail.h"
28 #include "wvpopclient.h"
30 #include <signal.h>
31 #include <assert.h>
32 #include <pwd.h>
33 #include <sys/types.h>
35 struct LogNum
37 int num;
38 const WvLog *src;
41 // cheesy hash function to do the job, basically
42 unsigned int WvHash(const WvLog *x)
44 return WvHash((int)x);
48 DeclareWvDict(LogNum, const WvLog *, src);
50 class RetchLog : public WvLogConsole
52 public:
53 RetchLog(WvLog::LogLevel _max_level)
54 : WvLogConsole(1, _max_level), lognums(5)
55 { maxnum = 0; }
56 virtual ~RetchLog() { }
58 virtual void _begin_line();
60 int maxnum;
61 LogNumDict lognums;
65 void RetchLog::_begin_line()
67 if (!strncmp(last_source->app, "PopRetriever ", 13))
69 LogNum *lognum = lognums[last_source];
70 if (!lognum)
72 lognum = new LogNum;
73 lognum->num = maxnum++;
74 lognum->src = last_source;
75 lognums.add(lognum, true);
78 // identify the connectionw without being too verbose
79 if (lognum->num < 26)
81 char str[2];
82 str[0] = 'A' + lognum->num;
83 str[1] = 0;
84 write(str);
86 else
87 write(lognum->num);
88 if (last_level <= WvLog::Info)
89 write("* ");
90 else
91 write(" ");
93 else
94 WvLogConsole::_begin_line(); // just print the whole thing
99 static volatile bool want_to_die = false;
100 void signal_handler(int signum)
102 fprintf(stderr, "\nCaught signal %d; cleaning up and terminating.\n",
103 signum);
104 want_to_die = true;
105 signal(signum, SIG_DFL);
109 static WvPopClient *newpop(WvIStreamList &l, WvStringParm acct,
110 WvStringParm _pass, WvStringParm _deliverto,
111 WvStringParm _mda, bool flush, bool apop_en,
112 bool apop_fall_en, bool explode)
115 WvString user(acct), serv, pass(_pass), deliverto(_deliverto),
116 mda(_mda);
117 bool ssl = false;
119 char *cptr = strrchr(user.edit(), '@');
120 if (cptr)
122 *cptr++ = 0;
123 serv = cptr;
125 else
126 serv = "localhost";
128 cptr = strchr(serv.edit(), ':');
129 if (!cptr)
131 serv.append(":110");
132 cptr = strchr(serv.edit(), ':'); // guaranteed to work now!
135 if (atoi(cptr+1) == 995)
136 ssl = true;
138 WvTCPConn *tcp = new WvTCPConn(serv);
139 WvStream *conn = tcp;
140 if (ssl) // FIXME: ssl verify should probably be set to something.
141 conn = new WvSSLStream(tcp, NULL);
143 return new WvPopClient(conn, l, acct, pass, deliverto, mda, flush, apop_en, apop_fall_en, explode);
147 static void usage(char *argv0, WvStringParm deliverto)
149 wvcon->print("Usage: %s [-d] [-dd] [-q] [-qq] [-V] [-F] [-c moniker ] "
150 "[-t deliverto] [acct...]\n"
151 " -d Print debug messages\n"
152 " -dd Print lots of debug messages\n"
153 " -q Quieter: don't print every message header\n"
154 " -qq Way quieter: only print errors\n"
155 " -V Print version and exit\n"
156 " -c Use <moniker> instead of "
157 "ini:~/.retchmail/retchmail\n"
158 " -F Flush (delete) messages after downloading\n"
159 " -E Send mail to the user on the system corresponding to the user the mail is sent to\n"
160 " -t Deliver mail to <deliverto> (default '%s')\n"
161 " acct... list of email accounts (username@host) to "
162 "retrieve from\n",
163 argv0, (const char *)deliverto);
164 exit(1);
167 extern char *optarg;
168 extern int optind;
171 int main(int argc, char **argv)
173 bool flush = false, explode = false;
174 int c, count;
175 WvLog::LogLevel lvl = WvLog::Debug1;
176 WvString deliverto("");
177 WvString confmoniker("");
179 // Set up WvCrash
180 wvcrash_setup(argv[0]);
182 // make sure electric fence works
183 free(malloc(1));
185 // Initialize wvcrash
186 wvcrash_setup(argv[0]);
188 signal(SIGPIPE, SIG_IGN);
190 struct passwd *pw = getpwuid(getuid());
191 if (pw)
192 deliverto = pw->pw_name;
194 while ((c = getopt(argc, argv, "dqVFEt:c:h?")) >= 0)
196 switch (c)
198 case 'd':
199 if (lvl <= WvLog::Debug1)
200 lvl = WvLog::Debug2;
201 else
202 lvl = WvLog::Debug5;
203 break;
204 case 'q':
205 if (lvl >= WvLog::Debug1)
206 lvl = WvLog::Info;
207 else
208 lvl = WvLog::Notice;
209 break;
210 case 'V':
211 wvcon->print("Retchmail version %s\n", RETCHMAIL_VER_STRING);
212 return 2;
213 case 'F':
214 flush = true;
215 break;
216 case 't':
217 deliverto = optarg;
218 break;
219 case 'c':
220 confmoniker = optarg;
221 break;
222 case 'E':
223 explode = true;
224 break;
225 case 'h':
226 case '?':
227 default:
228 usage(argv[0], deliverto);
229 break;
233 WvString lockname("/tmp/retchmail.%s.pid", getlogin());
234 WvLockFile lockfile(lockname);
236 if (!lockfile.lock())
238 if (lockfile.readpid() == -1)
239 fprintf(stderr, "retchmail: can't access lockfile at %s.\n",
240 lockname.cstr());
241 else
242 fprintf(stderr, "retchmail: already running (%i).\n",
243 lockfile.readpid());
244 return 3;
247 if (!deliverto)
249 fprintf(stderr, "retchmail: can't get username for uid#%u. "
250 "You must give the -t option.\n", getuid());
251 return 3;
255 RetchLog logrcv(lvl);
257 if (!confmoniker)
259 // attempting to use $HOME/.retchmail/retchmail.conf\n");
260 confmoniker = "ini:";
261 confmoniker.append(getenv("HOME"));
262 confmoniker.append("/.retchmail/retchmail.conf");
265 UniConfRoot cfg(confmoniker);
267 if (!cfg.haschildren())
269 wvcon->print("No data found, aborting\n");
270 exit(1);
273 WvIStreamList l;
274 WvPopClient *cli;
275 bool apop_enable = cfg["retchmail"]["Enable APOP"].getmeint(0);
276 bool apop_enable_fallback = cfg["retchmail"]["Enable APOP Fallback"].getmeint(0);
278 if (optind == argc)
280 UniConf sect = cfg["POP Servers"];
281 if (sect.haschildren())
283 UniConf::Iter i(sect);
284 for (i.rewind(); i.next(); )
286 cli = newpop(l, i->key(), i->getme(),
287 cfg["POP Targets"][i->key()].getme(deliverto),
288 cfg["MDA Override"][i->key()].getme(
289 "/usr/sbin/sendmail"),
290 flush, apop_enable, apop_enable_fallback,
291 explode ? : cfg["Explode"][i->key()].getmeint(0));
292 l.append(cli, true, "client");
295 else
297 fprintf(stderr, "\n-- No config file and no accounts given on the "
298 "command line!\n");
299 usage(argv[0], deliverto);
302 else
304 for (count = optind; count < argc; count++)
306 WvString pass = cfg["POP Servers"][argv[count]].getme();
307 if (!pass)
309 wvcon->print("Password for <%s>: ", argv[count]);
311 system("stty -echo 2>/dev/null");
312 pass = wvcon->blocking_getline(-1);
313 system("stty echo 2>/dev/null");
315 wvcon->print("\n");
318 cli = newpop(l, argv[count], pass,
319 cfg["POP Targets"][argv[count]].getme(deliverto),
320 cfg["MDA Override"][argv[count]].getme(
321 "/usr/sbin/sendmail"),
322 flush, apop_enable, apop_enable_fallback, explode);
323 l.append(cli, true, "client");
327 signal(SIGINT, signal_handler);
328 signal(SIGTERM, signal_handler);
330 while (!l.isempty() && !want_to_die)
332 if (l.select(1000))
333 l.callback();
336 lockfile.unlock();