1 /*
2 ** Copyright 2002-2006, Double Precision Inc.
3 **
4 ** See COPYING for distribution information.
5 */
6 #include "libmail_config.h"
7 #include "mboxadd.H"
8 #include "mboxsighandler.H"
9 #include "file.H"
10
11 #include <errno.h>
12 #include <pwd.h>
13 #include <time.h>
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17
18 using namespace std;
19
add(mail::mbox & mboxArg,string pathArg,mail::callback & callbackArg)20 mail::mbox::folder::add::add(mail::mbox &mboxArg, string pathArg,
21 mail::callback &callbackArg)
22 : mail::addMessage(&mboxArg), path(pathArg),
23 callback(callbackArg),
24 fp(tmpfile()),
25 mboxAccount(&mboxArg)
26 {
27 }
28
~add()29 mail::mbox::folder::add::~add()
30 {
31 if (fp)
32 fclose(fp);
33 }
34
saveMessageContents(string msg)35 void mail::mbox::folder::add::saveMessageContents(string msg)
36 {
37 if (msg.empty())
38 return;
39
40 if (fp)
41 if (fwrite(&msg[0], msg.size(), 1, fp) != 1)
42 ; // Ignore gcc warning
43 }
44
fail(string msg)45 void mail::mbox::folder::add::fail(string msg)
46 {
47 callback.fail(msg);
48 delete this;
49 }
50
success(string msg)51 void mail::mbox::folder::add::success(string msg)
52 {
53 callback.success(msg);
54 delete this;
55 }
56
reportProgress(size_t bytesCompleted,size_t bytesEstimatedTotal,size_t messagesCompleted,size_t messagesEstimatedTotal)57 void mail::mbox::folder::add::reportProgress(size_t bytesCompleted,
58 size_t bytesEstimatedTotal,
59
60 size_t messagesCompleted,
61 size_t messagesEstimatedTotal)
62 {
63 callback.reportProgress(bytesCompleted, bytesEstimatedTotal,
64 messagesCompleted, messagesEstimatedTotal);
65 }
66
go()67 void mail::mbox::folder::add::go()
68 {
69 if (!fp)
70 fail(strerror(errno));
71
72 if (mboxAccount.isDestroyed())
73 {
74 fail("Server connection aborted");
75 return;
76 }
77
78 try {
79 if (path == mboxAccount->currentFolder)
80 {
81 mboxAccount->installTask(new LockCurrentFolder( *this ));
82 }
83 else
84 {
85 mboxAccount->installTask(new LockCurrentFolder( *this,
86 path));
87 }
88 } catch (...) {
89 fail("An exception occured while adding message.");
90 return;
91 }
92 }
93
94 //
95 // Folder's now locked.
96 //
97
copyTo(mail::file & file)98 void mail::mbox::folder::add::copyTo(mail::file &file)
99 {
100 struct stat st;
101
102 mail::mbox::sighandler updating(fileno(static_cast<FILE *>(file)));
103
104 try {
105
106 // Make sure the mboxAccount file ends with a trailing newline
107
108 if (fstat(fileno(static_cast<FILE *>(file)), &st) < 0)
109 {
110 fail(strerror(errno));
111 return;
112 }
113
114 int ch='\n';
115
116 if (st.st_size > 0)
117 {
118 if (fseek(file, -1, SEEK_END) < 0 ||
119 (ch=getc(file)) == EOF)
120 {
121 fail(strerror(errno));
122 return;
123 }
124 }
125
126 if (fseek(file, 0L, SEEK_END) < 0 ||
127 fseek(fp, 0L, SEEK_SET) < 0)
128 {
129 fail(strerror(errno));
130 return;
131 }
132
133 if (ch != '\n')
134 putc('\n', file);
135
136 mail::file f(fileno(fp), "w+");
137
138 messageInfo.uid= mail::mboxMagicTag()
139 .getMessageInfo().uid;
140
141 string hdr=mail::mboxMagicTag(messageInfo.uid,
142 messageInfo,
143
144 mail::keywords::Message()
145 // KEYWORDS
146
147 ).toString();
148
149 struct passwd *pw;
150 pw=getpwuid(getuid());
151
152 fprintf(file, "From %s %s%s\n",
153 pw ? pw->pw_name:"nobody",
154 ctime(&messageDate),
155 hdr.c_str());
156
157 size_t bytesDone=0;
158 size_t bytesNextReport=0;
159
160 while (!feof(f))
161 {
162 string l=f.getline();
163
164 if (l.size() == 0 && feof(f))
165 break;
166
167 const char *p=l.c_str();
168
169 while (*p == '>')
170 p++;
171
172 if (strncmp(p, "From ", 5) == 0)
173 l=">" + l;
174
175 l += "\n";
176
177 if (fwrite(&l[0], l.size(), 1, file) != 1)
178 ; // Ignore gcc warning
179
180 bytesDone += l.size();
181
182 if (bytesDone >= bytesNextReport)
183 {
184 bytesNextReport=bytesDone + BUFSIZ;
185 callback.reportProgress(bytesDone, 0, 0, 1);
186 }
187 }
188
189 if (fflush(file) < 0 || ferror(file))
190 {
191 updating.rollback();
192 fail(strerror(errno));
193 return;
194 }
195
196 callback.reportProgress(bytesDone, bytesDone, 1, 1);
197 updating.block();
198 } catch (...) {
199 updating.rollback();
200 fail("An exception occured while adding message.");
201 return;
202 }
203
204 try {
205 fclose(fp);
206 fp=NULL;
207 success("OK");
208 } catch (...) {
209 delete this;
210 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
211 }
212 }
213
214 ///////////////////////////////////////////////////////////////////////////
215
216 mail::mbox::folder::add::LockCurrentFolder
LockCurrentFolder(add & meArg,string pathArg)217 ::LockCurrentFolder(add &meArg, string pathArg)
218 : LockTask(*meArg.mboxAccount, meArg, pathArg), me(meArg)
219 {
220 }
221
~LockCurrentFolder()222 mail::mbox::folder::add::LockCurrentFolder::~LockCurrentFolder()
223 {
224 }
225
226
locked(mail::file & lockedFile)227 bool mail::mbox::folder::add::LockCurrentFolder::locked(mail::file
228 &lockedFile)
229 {
230 // If the current folder is opened in read-only mode, this is a no-go.
231
232 if (me.path == me.mboxAccount->currentFolder && mboxAccount.currentFolderReadOnly)
233 {
234 me.fail("Folder opened in read-only mode.");
235 done();
236 return true;
237 }
238
239 me.copyTo(lockedFile);
240 done();
241 return true;
242 }
243