appendfiletombox.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #include "common.h"
  2. enum {
  3. Buffersize = 64*1024,
  4. };
  5. typedef struct Inbuf Inbuf;
  6. struct Inbuf
  7. {
  8. char buf[Buffersize];
  9. char *wp;
  10. char *rp;
  11. int eof;
  12. int in;
  13. int out;
  14. int last;
  15. ulong bytes;
  16. };
  17. static Inbuf*
  18. allocinbuf(int in, int out)
  19. {
  20. Inbuf *b;
  21. b = mallocz(sizeof(Inbuf), 1);
  22. if(b == nil)
  23. sysfatal("reading mailbox: %r");
  24. b->rp = b->wp = b->buf;
  25. b->in = in;
  26. b->out = out;
  27. return b;
  28. }
  29. /* should only be called at start of file or when b->rp[-1] == '\n' */
  30. static int
  31. fill(Inbuf *b, int addspace)
  32. {
  33. int i, n;
  34. if(b->eof && b->wp - b->rp == 0)
  35. return 0;
  36. n = b->rp - b->buf;
  37. if(n > 0){
  38. i = write(b->out, b->buf, n);
  39. if(i != n)
  40. return -1;
  41. b->last = b->buf[n-1];
  42. b->bytes += n;
  43. }
  44. if(addspace){
  45. if(write(b->out, " ", 1) != 1)
  46. return -1;
  47. b->last = ' ';
  48. b->bytes++;
  49. }
  50. n = b->wp - b->rp;
  51. memmove(b->buf, b->rp, n);
  52. b->rp = b->buf;
  53. b->wp = b->rp + n;
  54. i = read(b->in, b->buf+n, sizeof(b->buf)-n);
  55. if(i < 0)
  56. return -1;
  57. b->wp += i;
  58. return b->wp - b->rp;
  59. }
  60. enum { Fromlen = sizeof "From " - 1, };
  61. /* code to escape ' '*From' ' at the beginning of a line */
  62. int
  63. appendfiletombox(int in, int out)
  64. {
  65. int addspace, n, sol;
  66. char *p;
  67. Inbuf *b;
  68. seek(out, 0, 2);
  69. b = allocinbuf(in, out);
  70. addspace = 0;
  71. sol = 1;
  72. for(;;){
  73. if(b->wp - b->rp < Fromlen){
  74. /*
  75. * not enough unread bytes in buffer to match "From ",
  76. * so get some more. We must only inject a space at
  77. * the start of a line (one that begins with "From ").
  78. */
  79. if (b->rp == b->buf || b->rp[-1] == '\n') {
  80. n = fill(b, addspace);
  81. addspace = 0;
  82. } else
  83. n = fill(b, 0);
  84. if(n < 0)
  85. goto error;
  86. if(n == 0)
  87. break;
  88. if(n < Fromlen){ /* still can't match? */
  89. b->rp = b->wp;
  90. continue;
  91. }
  92. }
  93. /* state machine looking for ' '*From' ' */
  94. if(!sol){
  95. p = memchr(b->rp, '\n', b->wp - b->rp);
  96. if(p == nil)
  97. b->rp = b->wp;
  98. else{
  99. b->rp = p+1;
  100. sol = 1;
  101. }
  102. continue;
  103. } else {
  104. if(*b->rp == ' ' || strncmp(b->rp, "From ", Fromlen) != 0){
  105. b->rp++;
  106. continue;
  107. }
  108. addspace = 1;
  109. sol = 0;
  110. }
  111. }
  112. /* mailbox entries always terminate with two newlines */
  113. n = b->last == '\n' ? 1 : 2;
  114. if(write(out, "\n\n", n) != n)
  115. goto error;
  116. n += b->bytes;
  117. free(b);
  118. return n;
  119. error:
  120. free(b);
  121. return -1;
  122. }
  123. int
  124. appendfiletofile(int in, int out)
  125. {
  126. int n;
  127. Inbuf *b;
  128. seek(out, 0, 2);
  129. b = allocinbuf(in, out);
  130. for(;;){
  131. n = fill(b, 0);
  132. if(n < 0)
  133. goto error;
  134. if(n == 0)
  135. break;
  136. b->rp = b->wp;
  137. }
  138. n = b->bytes;
  139. free(b);
  140. return n;
  141. error:
  142. free(b);
  143. return -1;
  144. }