2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2018 Colin Leroy <colin@colino.net>
4 * and the Claws Mail team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * A mail which has been completely downloaded will have no special headers,
23 * and its entry in the uidl file will end by 0 (POP3_TOTALLY_RECEIVED);
25 * A mail which has been partially downloaded will have some special headers,
26 * and its entry in the uidl file will first be 1 (POP3_PARTIALLY_RECEIVED);
27 * the special headers will be including "SC-Marked-For-Download" which can
29 * 0 (POP3_PARTIAL_DLOAD_UNKN) meaning that the user has not yet chosen to
30 * download the mail or let it be deleted - this header is absent until the
31 * user first chooses an action
32 * 1 (POP3_PARTIAL_DLOAD_DLOAD) meaning that the user wants to finish
33 * downloading the mail
34 * 2 (POP3_PARTIAL_DLOAD_DELE) meaning that the user does not want to finish
35 * downloading the mail
36 * When updating this header to POP3_PARTIAL_DLOAD_DLOAD, the uidl line of
37 * this mail will end with the mail's physical path, which Claws Mail will remove
38 * after having downloaded the complete mail. msg->partial_recv will equal
39 * 2 (POP3_MUST_COMPLETE_RECV).
40 * When updating this header to POP3_PARTIAL_DLOAD_DELE, the uidl line of
41 * this mail will be 0 (POP3_TOTALLY_RECEIVED), which will let Claws Mail delete
42 * this mail from the server as soon as the leave_time preference specifies.
47 #include "claws-features.h"
51 #include <glib/gi18n.h>
60 #include "partial_download.h"
64 #include "procheader.h"
66 #include "file-utils.h"
68 int partial_msg_in_uidl_list(MsgInfo
*msginfo
)
72 gchar buf
[POPBUFSIZE
];
73 gchar uidl
[POPBUFSIZE
];
76 gchar
*sanitized_uid
= NULL
;
78 if (!msginfo
->extradata
)
81 sanitized_uid
= g_strdup(msginfo
->extradata
->account_login
);
83 subst_for_filename(sanitized_uid
);
85 if (!msginfo
->extradata
->account_server
86 || !msginfo
->extradata
->account_login
87 || !msginfo
->extradata
->partial_recv
)
90 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
91 "uidl", G_DIR_SEPARATOR_S
, msginfo
->extradata
->account_server
,
92 "-", msginfo
->extradata
->account_login
, NULL
);
93 if ((fp
= claws_fopen(path
, "rb")) == NULL
) {
94 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "claws_fopen");
96 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
97 "uidl-", msginfo
->extradata
->account_server
,
98 "-", sanitized_uid
, NULL
);
99 if ((fp
= claws_fopen(path
, "rb")) == NULL
) {
100 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "claws_fopen");
101 g_free(sanitized_uid
);
106 g_free(sanitized_uid
);
111 while (claws_fgets(buf
, sizeof(buf
), fp
) != NULL
) {
112 gchar tmp
[POPBUFSIZE
];
114 recv_time
= RECV_TIME_NONE
;
116 if (sscanf(buf
, "%s\t%ld\t%s", uidl
, (long int *) &recv_time
,
118 if (sscanf(buf
, "%s", uidl
) != 1)
124 if (!strcmp(uidl
, msginfo
->extradata
->partial_recv
)) {
134 static int partial_uidl_mark_mail(MsgInfo
*msginfo
, int download
)
140 gchar buf
[POPBUFSIZE
];
141 gchar uidl
[POPBUFSIZE
];
144 gchar partial_recv
[POPBUFSIZE
];
148 gchar
*sanitized_uid
= NULL
;
150 filename
= procmsg_get_message_file_path(msginfo
);
152 g_warning("can't get message file path");
155 tinfo
= procheader_parse_file(filename
, msginfo
->flags
, TRUE
, TRUE
);
157 if (!tinfo
->extradata
) {
162 sanitized_uid
= g_strdup(tinfo
->extradata
->account_login
);
163 subst_for_filename(sanitized_uid
);
165 if (!tinfo
->extradata
->account_server
166 || !tinfo
->extradata
->account_login
167 || !tinfo
->extradata
->partial_recv
) {
170 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
171 "uidl", G_DIR_SEPARATOR_S
, tinfo
->extradata
->account_server
,
172 "-", sanitized_uid
, NULL
);
174 if ((fp
= claws_fopen(path
, "rb")) == NULL
) {
175 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "claws_fopen");
177 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
178 "uidl-", tinfo
->extradata
->account_server
,
179 "-", tinfo
->extradata
->account_login
, NULL
);
180 if ((fp
= claws_fopen(path
, "rb")) == NULL
) {
181 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "claws_fopen");
187 pathnew
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
188 "uidl", G_DIR_SEPARATOR_S
, tinfo
->extradata
->account_server
,
189 "-", sanitized_uid
, ".new", NULL
);
191 g_free(sanitized_uid
);
193 if ((fpnew
= claws_fopen(pathnew
, "wb")) == NULL
) {
194 FILE_OP_ERROR(pathnew
, "claws_fopen");
203 while (claws_fgets(buf
, sizeof(buf
), fp
) != NULL
) {
205 recv_time
= RECV_TIME_NONE
;
206 sprintf(partial_recv
,"0");
208 if (sscanf(buf
, "%s\t%ld\t%s",
209 uidl
, (long int *) &recv_time
, partial_recv
) < 2) {
210 if (sscanf(buf
, "%s", uidl
) != 1)
216 if (strcmp(tinfo
->extradata
->partial_recv
, uidl
)) {
217 if (fprintf(fpnew
, "%s\t%ld\t%s\n",
218 uidl
, (long int) recv_time
, partial_recv
) < 0) {
219 FILE_OP_ERROR(pathnew
, "fprintf");
228 if (download
== POP3_PARTIAL_DLOAD_DLOAD
) {
229 gchar
*folder_id
= folder_item_get_identifier(
231 stat
= g_strdup_printf("%s:%d",
232 folder_id
, msginfo
->msgnum
);
235 else if (download
== POP3_PARTIAL_DLOAD_UNKN
)
236 stat
= g_strdup("1");
237 else if (download
== POP3_PARTIAL_DLOAD_DELE
)
238 stat
= g_strdup("0");
240 if (fprintf(fpnew
, "%s\t%ld\t%s\n",
241 uidl
, (long int) recv_time
, stat
) < 0) {
242 FILE_OP_ERROR(pathnew
, "fprintf");
252 if (claws_safe_fclose(fpnew
) == EOF
) {
253 FILE_OP_ERROR(pathnew
, "claws_fclose");
261 move_file(pathnew
, path
, TRUE
);
266 if ((fp
= claws_fopen(filename
,"rb")) == NULL
) {
267 FILE_OP_ERROR(filename
, "claws_fopen");
270 pathnew
= g_strdup_printf("%s.new", filename
);
271 if ((fpnew
= claws_fopen(pathnew
, "wb")) == NULL
) {
272 FILE_OP_ERROR(pathnew
, "claws_fopen");
278 if (fprintf(fpnew
, "SC-Marked-For-Download: %d\n",
280 FILE_OP_ERROR(pathnew
, "fprintf");
286 while (claws_fgets(buf
, sizeof(buf
)-1, fp
) != NULL
) {
287 if(strlen(buf
) > strlen("SC-Marked-For-Download: x\n")
288 && !strncmp(buf
, "SC-Marked-For-Download:",
289 strlen("SC-Marked-For-Download:"))) {
290 if (fprintf(fpnew
, "%s",
291 buf
+strlen("SC-Marked-For-Download: x\n")) < 0) {
292 FILE_OP_ERROR(pathnew
, "fprintf");
299 } else if (strlen(buf
) == strlen("SC-Marked-For-Download: x\n")
300 && !strncmp(buf
, "SC-Marked-For-Download:",
301 strlen("SC-Marked-For-Download:"))) {
304 if (fprintf(fpnew
, "%s", buf
) < 0) {
305 FILE_OP_ERROR(pathnew
, "fprintf");
312 if (claws_safe_fclose(fpnew
) == EOF
) {
313 FILE_OP_ERROR(pathnew
, "claws_fclose");
320 if (rename_force(pathnew
, filename
) != 0) {
326 msginfo
->planned_download
= download
;
327 msgcache_update_msg(msginfo
->folder
->cache
, msginfo
);
332 procmsg_msginfo_free(&tinfo
);
337 int partial_mark_for_delete(MsgInfo
*msginfo
)
339 return partial_uidl_mark_mail(msginfo
, POP3_PARTIAL_DLOAD_DELE
);
342 int partial_mark_for_download(MsgInfo
*msginfo
)
344 return partial_uidl_mark_mail(msginfo
, POP3_PARTIAL_DLOAD_DLOAD
);
347 int partial_unmark(MsgInfo
*msginfo
)
349 return partial_uidl_mark_mail(msginfo
, POP3_PARTIAL_DLOAD_UNKN
);
352 void partial_delete_old(const gchar
*file
)
354 gchar
*id
= g_strdup(file
);
355 gchar
*snum
= strrchr(file
, ':');
357 FolderItem
*item
= NULL
;
359 debug_print("too big message updated, should remove %s\n", file
?file
:"(null)");
365 return; /* not a real problem */
370 if (strrchr(id
, ':'))
371 *(strrchr(id
, ':'))='\0';
373 item
= folder_find_item_from_identifier(id
);
375 debug_print("removing %d in %s\n", num
, id
);
376 folder_item_remove_msg(item
, num
);
381 gchar
*partial_get_filename(const gchar
*server
, const gchar
*login
,
385 gchar
*result
= NULL
;
387 gchar buf
[POPBUFSIZE
];
388 gchar uidl
[POPBUFSIZE
];
391 gchar
*sanitized_uid
= g_strdup(login
);
393 subst_for_filename(sanitized_uid
);
395 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
396 "uidl", G_DIR_SEPARATOR_S
,
397 server
, "-", sanitized_uid
, NULL
);
398 if ((fp
= claws_fopen(path
, "rb")) == NULL
) {
399 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "claws_fopen");
401 path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
403 "-", sanitized_uid
, NULL
);
404 if ((fp
= claws_fopen(path
, "rb")) == NULL
) {
405 if (ENOENT
!= errno
) FILE_OP_ERROR(path
, "claws_fopen");
406 g_free(sanitized_uid
);
411 g_free(sanitized_uid
);
416 while (claws_fgets(buf
, sizeof(buf
), fp
) != NULL
) {
417 gchar tmp
[POPBUFSIZE
];
419 recv_time
= RECV_TIME_NONE
;
421 if (sscanf(buf
, "%s\t%ld\t%s", uidl
, (long int *) &recv_time
,
423 if (sscanf(buf
, "%s", uidl
) != 1)
429 if (!strcmp(muidl
, uidl
)) {
430 result
= g_strdup(tmp
);