Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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