1/* 2 * Copyright (c) 1998 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include <popper.h> 35#include <dirent.h> 36RCSID("$Id$"); 37 38static void 39make_path(POP *p, MsgInfoList *mp, int new, char *buf, size_t len) 40{ 41 snprintf(buf, len, "%s/%s%s%s", p->drop_name, 42 new ? "new" : "cur", mp ? "/" : "", mp ? mp->name : ""); 43} 44 45static int 46scan_file(POP *p, MsgInfoList *mp) 47{ 48 char path[MAXPATHLEN]; 49 FILE *f; 50 char buf[1024]; 51 int eoh = 0; 52 53 make_path(p, mp, mp->flags & NEW_FLAG, path, sizeof(path)); 54 f = fopen(path, "r"); 55 56 if(f == NULL) { 57#ifdef DEBUG 58 if(p->debug) 59 pop_log(p, POP_DEBUG, 60 "Failed to open message file `%s': %s", 61 path, strerror(errno)); 62#endif 63 return pop_msg (p, POP_FAILURE, 64 "Failed to open message file `%s'", path); 65 } 66 while(fgets(buf, sizeof(buf), f)) { 67 if(buf[strlen(buf) - 1] == '\n') 68 mp->lines++; 69 mp->length += strlen(buf); 70 if(eoh) 71 continue; 72 if(strcmp(buf, "\n") == 0) 73 eoh = 1; 74 parse_header(mp, buf); 75 } 76 fclose(f); 77 return add_missing_headers(p, mp); 78} 79 80static int 81scan_dir(POP *p, int new) 82{ 83 char tmp[MAXPATHLEN]; 84 DIR *dir; 85 struct dirent *dent; 86 MsgInfoList *mp = p->mlp; 87 int n_mp = p->msg_count; 88 int e; 89 90 make_path(p, NULL, new, tmp, sizeof(tmp)); 91 mkdir(tmp, 0700); 92 dir = opendir(tmp); 93 while((dent = readdir(dir)) != NULL) { 94 if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) 95 continue; 96 mp = realloc(mp, (n_mp + 1) * sizeof(*mp)); 97 if(mp == NULL) { 98 p->msg_count = 0; 99 return pop_msg (p, POP_FAILURE, 100 "Can't build message list for '%s': Out of memory", 101 p->user); 102 } 103 memset(mp + n_mp, 0, sizeof(*mp)); 104 mp[n_mp].name = strdup(dent->d_name); 105 if(mp[n_mp].name == NULL) { 106 p->msg_count = 0; 107 return pop_msg (p, POP_FAILURE, 108 "Can't build message list for '%s': Out of memory", 109 p->user); 110 } 111 mp[n_mp].number = n_mp + 1; 112 mp[n_mp].flags = 0; 113 if(new) 114 mp[n_mp].flags |= NEW_FLAG; 115 e = scan_file(p, &mp[n_mp]); 116 if(e != POP_SUCCESS) 117 return e; 118 p->drop_size += mp[n_mp].length; 119 n_mp++; 120 } 121 closedir(dir); 122 p->mlp = mp; 123 p->msg_count = n_mp; 124 return POP_SUCCESS; 125} 126 127int 128pop_maildir_info(POP *p) 129{ 130 int e; 131 132 p->temp_drop[0] = '\0'; 133 p->mlp = NULL; 134 p->msg_count = 0; 135 136 e = scan_dir(p, 0); 137 if(e != POP_SUCCESS) return e; 138 139 e = scan_dir(p, 1); 140 if(e != POP_SUCCESS) return e; 141 return POP_SUCCESS; 142} 143 144int 145pop_maildir_update(POP *p) 146{ 147 int i; 148 char tmp1[MAXPATHLEN], tmp2[MAXPATHLEN]; 149 for(i = 0; i < p->msg_count; i++) { 150 make_path(p, &p->mlp[i], p->mlp[i].flags & NEW_FLAG, 151 tmp1, sizeof(tmp1)); 152 if(p->mlp[i].flags & DEL_FLAG) { 153#ifdef DEBUG 154 if(p->debug) 155 pop_log(p, POP_DEBUG, "Removing `%s'", tmp1); 156#endif 157 if(unlink(tmp1) < 0) { 158#ifdef DEBUG 159 if(p->debug) 160 pop_log(p, POP_DEBUG, "Failed to remove `%s': %s", 161 tmp1, strerror(errno)); 162#endif 163 /* return failure? */ 164 } 165 } else if((p->mlp[i].flags & NEW_FLAG) && 166 (p->mlp[i].flags & RETR_FLAG)) { 167 make_path(p, &p->mlp[i], 0, tmp2, sizeof(tmp2)); 168#ifdef DEBUG 169 if(p->debug) 170 pop_log(p, POP_DEBUG, "Linking `%s' to `%s'", tmp1, tmp2); 171#endif 172 if(link(tmp1, tmp2) == 0) { 173#ifdef DEBUG 174 if(p->debug) 175 pop_log(p, POP_DEBUG, "Removing `%s'", tmp1); 176#endif 177 if(unlink(tmp1) < 0) { 178#ifdef DEBUG 179 if(p->debug) 180 pop_log(p, POP_DEBUG, "Failed to remove `%s'", tmp1); 181#endif 182 /* return failure? */ 183 } 184 } else { 185 if(errno == EXDEV) { 186#ifdef DEBUG 187 if(p->debug) 188 pop_log(p, POP_DEBUG, "Trying to rename `%s' to `%s'", 189 tmp1, tmp2); 190#endif 191 if(rename(tmp1, tmp2) < 0) { 192#ifdef DEBUG 193 if(p->debug) 194 pop_log(p, POP_DEBUG, "Failed to rename `%s' to `%s'", 195 tmp1, tmp2); 196#endif 197 } 198 } 199 } 200 } 201 } 202 return(pop_quit(p)); 203} 204 205int 206pop_maildir_open(POP *p, MsgInfoList *mp) 207{ 208 char tmp[MAXPATHLEN]; 209 make_path(p, mp, mp->flags & NEW_FLAG, tmp, sizeof(tmp)); 210 if(p->drop) 211 fclose(p->drop); 212 p->drop = fopen(tmp, "r"); 213 if(p->drop == NULL) 214 return pop_msg(p, POP_FAILURE, "Failed to open message file"); 215 return POP_SUCCESS; 216} 217