copy.c 4.9 KB

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