plumb.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <plumb.h>
  5. #include <regexp.h>
  6. #include <bio.h>
  7. #include "faces.h"
  8. static int showfd = -1;
  9. static int seefd = -1;
  10. static int logfd = -1;
  11. static char *user;
  12. static char *logtag;
  13. char **maildirs;
  14. int nmaildirs;
  15. void
  16. initplumb(void)
  17. {
  18. showfd = plumbopen("send", OWRITE);
  19. seefd = plumbopen("seemail", OREAD);
  20. if(seefd < 0){
  21. logfd = open("/sys/log/mail", OREAD);
  22. seek(logfd, 0LL, 2);
  23. user = getenv("user");
  24. if(user == nil){
  25. fprint(2, "faces: can't find user name: %r\n");
  26. exits("$user");
  27. }
  28. logtag = emalloc(32+strlen(user)+1);
  29. sprint(logtag, " delivered %s From ", user);
  30. }
  31. }
  32. void
  33. addmaildir(char *dir)
  34. {
  35. maildirs = erealloc(maildirs, (nmaildirs+1)*sizeof(char*));
  36. maildirs[nmaildirs++] = dir;
  37. }
  38. char*
  39. attr(Face *f)
  40. {
  41. static char buf[128];
  42. if(f->str[Sdigest]){
  43. snprint(buf, sizeof buf, "digest=%s", f->str[Sdigest]);
  44. return buf;
  45. }
  46. return nil;
  47. }
  48. void
  49. showmail(Face *f)
  50. {
  51. char *s;
  52. int n;
  53. if(showfd<0 || f->str[Sshow]==nil || f->str[Sshow][0]=='\0')
  54. return;
  55. s = emalloc(128+strlen(f->str[Sshow])+1);
  56. n = sprint(s, "faces\nshowmail\n/mail/fs/\ntext\n%s\n%ld\n%s", attr(f), strlen(f->str[Sshow]), f->str[Sshow]);
  57. write(showfd, s, n);
  58. free(s);
  59. }
  60. char*
  61. value(Plumbattr *attr, char *key, char *def)
  62. {
  63. char *v;
  64. v = plumblookup(attr, key);
  65. if(v)
  66. return v;
  67. return def;
  68. }
  69. void
  70. setname(Face *f, char *sender)
  71. {
  72. char *at, *bang;
  73. char *p;
  74. /* works with UTF-8, although it's written as ASCII */
  75. for(p=sender; *p!='\0'; p++)
  76. *p = tolower(*p);
  77. f->str[Suser] = sender;
  78. at = strchr(sender, '@');
  79. if(at){
  80. *at++ = '\0';
  81. f->str[Sdomain] = estrdup(at);
  82. return;
  83. }
  84. bang = strchr(sender, '!');
  85. if(bang){
  86. *bang++ = '\0';
  87. f->str[Suser] = estrdup(bang);
  88. f->str[Sdomain] = sender;
  89. return;
  90. }
  91. }
  92. int
  93. getc(void)
  94. {
  95. static uchar buf[512];
  96. static int nbuf = 0;
  97. static int i = 0;
  98. while(i == nbuf){
  99. i = 0;
  100. nbuf = read(logfd, buf, sizeof buf);
  101. if(nbuf == 0){
  102. sleep(15000);
  103. continue;
  104. }
  105. if(nbuf < 0)
  106. return -1;
  107. }
  108. return buf[i++];
  109. }
  110. char*
  111. getline(char *buf, int n)
  112. {
  113. int i, c;
  114. for(i=0; i<n-1; i++){
  115. c = getc();
  116. if(c <= 0)
  117. return nil;
  118. if(c == '\n')
  119. break;
  120. buf[i] = c;
  121. }
  122. buf[i] = '\0';
  123. return buf;
  124. }
  125. static char* months[] = {
  126. "jan", "feb", "mar", "apr",
  127. "may", "jun", "jul", "aug",
  128. "sep", "oct", "nov", "dec"
  129. };
  130. static int
  131. getmon(char *s)
  132. {
  133. int i;
  134. for(i=0; i<nelem(months); i++)
  135. if(cistrcmp(months[i], s) == 0)
  136. return i;
  137. return -1;
  138. }
  139. /* Fri Jul 23 14:05:14 EDT 1999 */
  140. ulong
  141. parsedatev(char **a)
  142. {
  143. char *p;
  144. Tm tm;
  145. memset(&tm, 0, sizeof tm);
  146. if((tm.mon=getmon(a[1])) == -1)
  147. goto Err;
  148. tm.mday = strtol(a[2], &p, 10);
  149. if(*p != '\0')
  150. goto Err;
  151. tm.hour = strtol(a[3], &p, 10);
  152. if(*p != ':')
  153. goto Err;
  154. tm.min = strtol(p+1, &p, 10);
  155. if(*p != ':')
  156. goto Err;
  157. tm.sec = strtol(p+1, &p, 10);
  158. if(*p != '\0')
  159. goto Err;
  160. if(strlen(a[4]) != 3)
  161. goto Err;
  162. strcpy(tm.zone, a[4]);
  163. if(strlen(a[5]) != 4)
  164. goto Err;
  165. tm.year = strtol(a[5], &p, 10);
  166. if(*p != '\0')
  167. goto Err;
  168. tm.year -= 1900;
  169. return tm2sec(&tm);
  170. Err:
  171. return time(0);
  172. }
  173. ulong
  174. parsedate(char *s)
  175. {
  176. char *f[10];
  177. int nf;
  178. nf = getfields(s, f, nelem(f), 1, " ");
  179. if(nf < 6)
  180. return time(0);
  181. return parsedatev(f);
  182. }
  183. /* achille Jul 23 14:05:15 delivered jmk From ms.com!bub Fri Jul 23 14:05:14 EDT 1999 (plan9.bell-labs.com!jmk) 1352 */
  184. /* achille Oct 26 13:45:42 remote local!rsc From rsc Sat Oct 26 13:45:41 EDT 2002 (rsc) 170 */
  185. int
  186. parselog(char *s, char **sender, ulong *xtime)
  187. {
  188. char *f[20];
  189. int nf;
  190. nf = getfields(s, f, nelem(f), 1, " ");
  191. if(nf < 14)
  192. return 0;
  193. if(strcmp(f[4], "delivered") == 0 && strcmp(f[5], user) == 0)
  194. goto Found;
  195. if(strcmp(f[4], "remote") == 0 && strncmp(f[5], "local!", 6) == 0 && strcmp(f[5]+6, user) == 0)
  196. goto Found;
  197. return 0;
  198. Found:
  199. *sender = estrdup(f[7]);
  200. *xtime = parsedatev(&f[8]);
  201. return 1;
  202. }
  203. int
  204. logrecv(char **sender, ulong *xtime)
  205. {
  206. char buf[4096];
  207. for(;;){
  208. if(getline(buf, sizeof buf) == nil)
  209. return 0;
  210. if(parselog(buf, sender, xtime))
  211. return 1;
  212. }
  213. return -1;
  214. }
  215. char*
  216. tweakdate(char *d)
  217. {
  218. char e[8];
  219. /* d, date = "Mon Aug 2 23:46:55 EDT 1999" */
  220. if(strlen(d) < strlen("Mon Aug 2 23:46:55 EDT 1999"))
  221. return estrdup("");
  222. if(strncmp(date, d, 4+4+3) == 0)
  223. snprint(e, sizeof e, "%.5s", d+4+4+3); /* 23:46 */
  224. else
  225. snprint(e, sizeof e, "%.6s", d+4); /* Aug 2 */
  226. return estrdup(e);
  227. }
  228. Face*
  229. nextface(void)
  230. {
  231. int i;
  232. Face *f;
  233. Plumbmsg *m;
  234. char *t, *senderp, *showmailp, *digestp;
  235. ulong xtime;
  236. f = emalloc(sizeof(Face));
  237. for(;;){
  238. if(seefd >= 0){
  239. m = plumbrecv(seefd);
  240. if(m == nil)
  241. killall("error on seemail plumb port");
  242. t = value(m->attr, "mailtype", "");
  243. if(strcmp(t, "delete") == 0)
  244. delete(m->data, value(m->attr, "digest", nil));
  245. else if(strcmp(t, "new") != 0)
  246. fprint(2, "faces: unknown plumb message type %s\n", t);
  247. else for(i=0; i<nmaildirs; i++)
  248. if(strncmp(m->data, maildirs[i], strlen(maildirs[i])) == 0)
  249. goto Found;
  250. plumbfree(m);
  251. continue;
  252. Found:
  253. xtime = parsedate(value(m->attr, "date", date));
  254. digestp = value(m->attr, "digest", nil);
  255. if(alreadyseen(digestp)){
  256. /* duplicate upas/fs can send duplicate messages */
  257. plumbfree(m);
  258. continue;
  259. }
  260. senderp = estrdup(value(m->attr, "sender", "???"));
  261. showmailp = estrdup(m->data);
  262. if(digestp)
  263. digestp = estrdup(digestp);
  264. plumbfree(m);
  265. }else{
  266. if(logrecv(&senderp, &xtime) <= 0)
  267. killall("error reading log file");
  268. showmailp = estrdup("");
  269. digestp = nil;
  270. }
  271. setname(f, senderp);
  272. f->time = xtime;
  273. f->tm = *localtime(xtime);
  274. f->str[Sshow] = showmailp;
  275. f->str[Sdigest] = digestp;
  276. return f;
  277. }
  278. return nil;
  279. }
  280. char*
  281. iline(char *data, char **pp)
  282. {
  283. char *p;
  284. for(p=data; *p!='\0' && *p!='\n'; p++)
  285. ;
  286. if(*p == '\n')
  287. *p++ = '\0';
  288. *pp = p;
  289. return data;
  290. }
  291. Face*
  292. dirface(char *dir, char *num)
  293. {
  294. Face *f;
  295. char *from, *date;
  296. char buf[1024], pwd[1024], *info, *p, *digest;
  297. int n, fd;
  298. ulong len;
  299. /*
  300. * loadmbox leaves us in maildir, so we needn't
  301. * walk /mail/fs/mbox for each face; this makes startup
  302. * a fair bit quicker.
  303. */
  304. if(getwd(pwd, sizeof pwd) != nil && strcmp(pwd, dir) == 0)
  305. sprint(buf, "%s/info", num);
  306. else
  307. sprint(buf, "%s/%s/info", dir, num);
  308. len = dirlen(buf);
  309. if(len <= 0)
  310. return nil;
  311. fd = open(buf, OREAD);
  312. if(fd < 0)
  313. return nil;
  314. info = emalloc(len+1);
  315. n = readn(fd, info, len);
  316. close(fd);
  317. if(n < 0){
  318. free(info);
  319. return nil;
  320. }
  321. info[n] = '\0';
  322. f = emalloc(sizeof(Face));
  323. from = iline(info, &p); /* from */
  324. iline(p, &p); /* to */
  325. iline(p, &p); /* cc */
  326. iline(p, &p); /* replyto */
  327. date = iline(p, &p); /* date */
  328. setname(f, estrdup(from));
  329. f->time = parsedate(date);
  330. f->tm = *localtime(f->time);
  331. sprint(buf, "%s/%s", dir, num);
  332. f->str[Sshow] = estrdup(buf);
  333. iline(p, &p); /* subject */
  334. iline(p, &p); /* mime content type */
  335. iline(p, &p); /* mime disposition */
  336. iline(p, &p); /* filename */
  337. digest = iline(p, &p); /* digest */
  338. f->str[Sdigest] = estrdup(digest);
  339. free(info);
  340. return f;
  341. }