7 #define SUBSCRIBED "imap.subscribed"
9 static int matches(char *ref, char *pat, char *name);
10 static int mayMatch(char *pat, char *name, int star);
11 static int checkMatch(char *cmd, char *ref, char *pat, char *mbox, long mtime, int isdir);
12 static int listAll(char *cmd, char *ref, char *pat, char *mbox, long mtime);
13 static int listMatch(char *cmd, char *ref, char *pat, char *mbox, char *mm);
14 static int mkSubscribed(void);
22 d = cdDirstat(mboxDir, file);
31 * check for subscribed mailboxes
32 * each line is either a comment starting with #
33 * or is a subscribed mailbox name
36 lsubBoxes(char *cmd, char *ref, char *pat)
48 fd = cdOpen(mboxDir, SUBSCRIBED, OREAD);
56 Binit(&bin, fd, OREAD);
57 while(s = Brdline(&bin, '\n')){
58 s[Blinelen(&bin) - 1] = '\0';
62 if(cistrcmp(s, "INBOX") == 0){
63 if(access("msgs", AEXIST) == 0)
64 mtime = listMtime("msgs");
66 mtime = listMtime("mbox");
69 d = cdDirstat(mboxDir, s);
72 if(!(d->mode & DMDIR))
78 ok |= checkMatch(cmd, ref, pat, s, mtime, isdir);
91 fd = cdCreate(mboxDir, SUBSCRIBED, ORDWR, 0664);
94 fprint(fd, "#imap4 subscription list\nINBOX\n");
100 * either subscribe or unsubscribe to a mailbox
103 subscribe(char *mbox, int how)
107 int fd, tfd, ok, nmbox;
109 if(cistrcmp(mbox, "inbox") == 0)
114 fd = cdOpen(mboxDir, SUBSCRIBED, ORDWR);
126 nmbox = strlen(mbox);
127 s = strstr(in, mbox);
128 while(s != nil && (s != in && s[-1] != '\n' || s[nmbox] != '\n'))
129 s = strstr(s+1, mbox);
131 if(how == 's' && s == nil){
132 if(fprint(fd, "%s\n", mbox) > 0)
134 }else if(how == 'u' && s != nil){
135 ein = strchr(s, '\0');
136 memmove(s, &s[nmbox+1], ein - &s[nmbox+1]);
138 tfd = cdOpen(mboxDir, SUBSCRIBED, OWRITE|OTRUNC);
139 if(tfd >= 0 && seek(fd, 0, 0) >= 0 && write(fd, in, ein-in) == ein-in)
151 * stupidly complicated so that % doesn't read entire directory structure
153 * note: in most places, inbox is case-insensitive,
154 * but here INBOX is checked for a case-sensitve match.
157 listBoxes(char *cmd, char *ref, char *pat)
161 ok = checkMatch(cmd, ref, pat, "INBOX", listMtime("mbox"), 0);
162 return ok | listMatch(cmd, ref, pat, ref, pat);
166 * look for all messages which may match the pattern
167 * punt when a * is reached
170 listMatch(char *cmd, char *ref, char *pat, char *mbox, char *mm)
173 char *mdir, *m, *mb, *wc;
175 int c, i, nmb, nmdir, nd, ok, fd;
178 for(m = mm; c = *m; m++){
179 if(c == '%' || c == '*'){
181 fd = cdOpen(mboxDir, ".", OREAD);
188 fd = cdOpen(mboxDir, mbox, OREAD);
190 nmdir = mdir - mbox + 1;
207 nmb = nmdir + strlen(m) + MboxNameLen + 3;
209 strncpy(mb, mbox, nmdir);
211 while((nd = dirread(fd, &dirs)) > 0){
212 for(i = 0; i < nd; i++){
213 if(strcmp(mbox, "") == 0 &&
214 !okMbox(dirs[i].name))
216 /* Safety: ignore message dirs */
217 if(strstr(dirs[i].name, "mails") != 0 ||
218 strcmp(dirs[i].name, "out") == 0 ||
219 strcmp(dirs[i].name, "obox") == 0 ||
220 strcmp(dirs[i].name, "ombox") == 0)
222 if(strcmp(dirs[i].name, "msgs") == 0)
223 dirs[i].mode &= ~DMDIR;
224 if(*wc == '*' && dirs[i].mode & DMDIR &&
225 mayMatch(mm, dirs[i].name, 1)){
226 snprint(mb+nmdir, nmb-nmdir,
228 ok |= listAll(cmd, ref, pat, mb,
230 }else if(mayMatch(mm, dirs[i].name, 0)){
231 snprint(mb+nmdir, nmb-nmdir,
232 "%s%s", dirs[i].name, m);
234 ok |= checkMatch(cmd,
239 else if(dirs[i].mode & DMDIR)
260 dir = cdDirstat(mboxDir, m);
263 ok = checkMatch(cmd, ref, pat, mbox, dir->mtime, (dir->mode & DMDIR) == DMDIR);
269 * too hard: recursively list all files rooted at mbox,
270 * and list checkMatch figure it out
273 listAll(char *cmd, char *ref, char *pat, char *mbox, long mtime)
277 int i, nmb, nd, ok, fd;
279 ok = checkMatch(cmd, ref, pat, mbox, mtime, 1);
280 fd = cdOpen(mboxDir, mbox, OREAD);
284 nmb = strlen(mbox) + MboxNameLen + 2;
286 while((nd = dirread(fd, &dirs)) > 0){
287 for(i = 0; i < nd; i++){
288 snprint(mb, nmb, "%s/%s", mbox, dirs[i].name);
289 /* safety: do not recurr */
290 if(0 && dirs[i].mode & DMDIR)
291 ok |= listAll(cmd, ref, pat, mb, dirs[i].mtime);
293 ok |= checkMatch(cmd, ref, pat, mb, dirs[i].mtime, 0);
303 mayMatch(char *pat, char *name, int star)
308 for(; *pat && *pat != '/'; pat += n){
313 n = chartorune(&r, pat);
315 if(r == '*' || r == '%'){
317 if(r == '*' && star || *pat == '\0' || *pat == '/')
320 if(mayMatch(pat, name, star))
322 name += chartorune(&r, name);
326 for(i = 0; i < n; i++)
327 if(name[i] != pat[i])
337 * mbox is a mailbox name which might match pat.
342 checkMatch(char *cmd, char *ref, char *pat, char *mbox, long mtime, int isdir)
346 if(!matches(ref, pat, mbox) || !okMbox(mbox))
348 if(strcmp(mbox, ".") == 0)
352 flags = "(\\Noselect)";
355 if(s != nil && listMtime(s) < mtime)
356 flags = "(\\Noinferiors \\Marked)";
358 flags = "(\\Noinferiors)";
363 Bprint(&bout, "* %s %s \"/\" \"%s\"\r\n", cmd, flags, s);
368 matches(char *ref, char *pat, char *name)
374 if(*name++ != *ref++)
376 for(; *pat; pat += n){
381 n = chartorune(&r, pat);
388 if(matches(pat, pat, name))
390 name += chartorune(&r, name);
396 while(*name && *name != '/'){
397 if(matches(pat, pat, name))
399 name += chartorune(&r, name);
404 for(i = 0; i < n; i++)
405 if(name[i] != pat[i])