copy.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <auth.h>
  5. #include <libsec.h>
  6. #include "imap4d.h"
  7. static int saveMsg(char *dst, char *digest, int flags, char *head, int nhead, Biobuf *b, long n);
  8. static int saveb(int fd, DigestState *dstate, char *buf, int nr, int nw);
  9. static long appSpool(Biobuf *bout, Biobuf *bin, long n);
  10. /*
  11. * check if the message exists
  12. */
  13. int
  14. copyCheck(Box *box, Msg *m, int uids, void *v)
  15. {
  16. int fd;
  17. USED(box);
  18. USED(uids);
  19. USED(v);
  20. if(m->expunged)
  21. return 0;
  22. fd = msgFile(m, "raw");
  23. if(fd < 0){
  24. msgDead(m);
  25. return 0;
  26. }
  27. close(fd);
  28. return 1;
  29. }
  30. int
  31. copySave(Box *box, Msg *m, int uids, void *vs)
  32. {
  33. Dir *d;
  34. Biobuf b;
  35. vlong length;
  36. char *head;
  37. int ok, hfd, bfd, nhead;
  38. USED(box);
  39. USED(uids);
  40. if(m->expunged)
  41. return 0;
  42. hfd = msgFile(m, "unixheader");
  43. if(hfd < 0){
  44. msgDead(m);
  45. return 0;
  46. }
  47. head = readFile(hfd);
  48. if(head == nil){
  49. close(hfd);
  50. return 0;
  51. }
  52. /*
  53. * clear out the header if it doesn't end in a newline,
  54. * since it is a runt and the "header" will show up in the raw file.
  55. */
  56. nhead = strlen(head);
  57. if(nhead > 0 && head[nhead-1] != '\n')
  58. nhead = 0;
  59. bfd = msgFile(m, "raw");
  60. close(hfd);
  61. if(bfd < 0){
  62. msgDead(m);
  63. return 0;
  64. }
  65. d = dirfstat(bfd);
  66. if(d == nil){
  67. close(bfd);
  68. return 0;
  69. }
  70. length = d->length;
  71. free(d);
  72. Binit(&b, bfd, OREAD);
  73. ok = saveMsg(vs, m->info[IDigest], m->flags, head, nhead, &b, length);
  74. Bterm(&b);
  75. close(bfd);
  76. return ok;
  77. }
  78. /*
  79. * first spool the input into a temorary file,
  80. * and massage the input in the process.
  81. * then save to real box.
  82. */
  83. int
  84. appendSave(char *mbox, int flags, char *head, Biobuf *b, long n)
  85. {
  86. Biobuf btmp;
  87. int fd, ok;
  88. fd = imapTmp();
  89. if(fd < 0)
  90. return 0;
  91. Bprint(&bout, "+ Ready for literal data\r\n");
  92. if(Bflush(&bout) < 0)
  93. writeErr();
  94. Binit(&btmp, fd, OWRITE);
  95. n = appSpool(&btmp, b, n);
  96. Bterm(&btmp);
  97. if(n < 0){
  98. close(fd);
  99. return 0;
  100. }
  101. seek(fd, 0, 0);
  102. Binit(&btmp, fd, OREAD);
  103. ok = saveMsg(mbox, nil, flags, head, strlen(head), &btmp, n);
  104. Bterm(&btmp);
  105. close(fd);
  106. return ok;
  107. }
  108. /*
  109. * copy from bin to bout,
  110. * mapping "\r\n" to "\n" and "\nFrom " to "\n From "
  111. * return the number of bytes in the mapped file.
  112. *
  113. * exactly n bytes must be read from the input,
  114. * unless an input error occurs.
  115. */
  116. static long
  117. appSpool(Biobuf *bout, Biobuf *bin, long n)
  118. {
  119. int i, c;
  120. c = '\n';
  121. while(n > 0){
  122. if(c == '\n' && n >= STRLEN("From ")){
  123. for(i = 0; i < STRLEN("From "); i++){
  124. c = Bgetc(bin);
  125. if(c != "From "[i]){
  126. if(c < 0)
  127. return -1;
  128. Bungetc(bin);
  129. break;
  130. }
  131. n--;
  132. }
  133. if(i == STRLEN("From "))
  134. Bputc(bout, ' ');
  135. Bwrite(bout, "From ", i);
  136. }
  137. c = Bgetc(bin);
  138. n--;
  139. if(c == '\r' && n-- > 0){
  140. c = Bgetc(bin);
  141. if(c != '\n')
  142. Bputc(bout, '\r');
  143. }
  144. if(c < 0)
  145. return -1;
  146. if(Bputc(bout, c) < 0)
  147. return -1;
  148. }
  149. if(c != '\n')
  150. Bputc(bout, '\n');
  151. if(Bflush(bout) < 0)
  152. return -1;
  153. return Boffset(bout);
  154. }
  155. static int
  156. saveMsg(char *dst, char *digest, int flags, char *head, int nhead, Biobuf *b, long n)
  157. {
  158. DigestState *dstate;
  159. MbLock *ml;
  160. uchar shadig[SHA1dlen];
  161. char buf[BufSize + 1], digbuf[NDigest + 1];
  162. int i, fd, nr, nw, ok;
  163. ml = mbLock();
  164. if(ml == nil)
  165. return 0;
  166. fd = openLocked(mboxDir, dst, OWRITE);
  167. if(fd < 0){
  168. mbUnlock(ml);
  169. return 0;
  170. }
  171. seek(fd, 0, 2);
  172. dstate = nil;
  173. if(digest == nil)
  174. dstate = sha1(nil, 0, nil, nil);
  175. if(!saveb(fd, dstate, head, nhead, nhead)){
  176. if(dstate != nil)
  177. sha1(nil, 0, shadig, dstate);
  178. mbUnlock(ml);
  179. close(fd);
  180. return 0;
  181. }
  182. ok = 1;
  183. if(n == 0)
  184. ok = saveb(fd, dstate, "\n", 0, 1);
  185. while(n > 0){
  186. nr = n;
  187. if(nr > BufSize)
  188. nr = BufSize;
  189. nr = Bread(b, buf, nr);
  190. if(nr <= 0){
  191. saveb(fd, dstate, "\n\n", 0, 2);
  192. ok = 0;
  193. break;
  194. }
  195. n -= nr;
  196. nw = nr;
  197. if(n == 0){
  198. if(buf[nw - 1] != '\n')
  199. buf[nw++] = '\n';
  200. buf[nw++] = '\n';
  201. }
  202. if(!saveb(fd, dstate, buf, nr, nw)){
  203. ok = 0;
  204. break;
  205. }
  206. mbLockRefresh(ml);
  207. }
  208. close(fd);
  209. if(dstate != nil){
  210. digest = digbuf;
  211. sha1(nil, 0, shadig, dstate);
  212. for(i = 0; i < SHA1dlen; i++)
  213. snprint(digest+2*i, NDigest+1-2*i, "%2.2ux", shadig[i]);
  214. }
  215. if(ok){
  216. fd = cdOpen(mboxDir, impName(dst), OWRITE);
  217. if(fd < 0)
  218. fd = emptyImp(dst);
  219. if(fd >= 0){
  220. seek(fd, 0, 2);
  221. wrImpFlags(buf, flags, 1);
  222. fprint(fd, "%.*s %.*lud %s\n", NDigest, digest, NUid, 0UL, buf);
  223. close(fd);
  224. }
  225. }
  226. mbUnlock(ml);
  227. return 1;
  228. }
  229. static int
  230. saveb(int fd, DigestState *dstate, char *buf, int nr, int nw)
  231. {
  232. if(dstate != nil)
  233. sha1((uchar*)buf, nr, nil, dstate);
  234. if(write(fd, buf, nw) != nw)
  235. return 0;
  236. return 1;
  237. }