plumb.c 6.8 KB

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