static struct imaptoken *do_readtoken(int touc) { int c=0; unsigned l; #define appendch(c) alloc_tokenbuf(l+1); curtoken.tokenbuf[l++]=(c); if (curtoken.tokentype == IT_ERROR) return (&curtoken); do { c=READ(); } while (c == '\r' || c == ' ' || c == '\t'); if (c == '\n') { UNREAD(c); curtoken.tokentype=IT_EOL; return (&curtoken); } c=(unsigned char)c; if (c == LPAREN_CHAR) { curtoken.tokentype=IT_LPAREN; return (&curtoken); } if (c == RPAREN_CHAR) { curtoken.tokentype=IT_RPAREN; return (&curtoken); } if (c == LBRACKET_CHAR) { curtoken.tokentype=IT_LBRACKET; return (&curtoken); } if (c == RBRACKET_CHAR) { curtoken.tokentype=IT_RBRACKET; return (&curtoken); } if (c == '"') { l=0; while ((c=READ()) != '"') { if (c == '\\') c=READ(); if (c == '\r' || c == '\n') { UNREAD(c); curtoken.tokentype=IT_ERROR; return (&curtoken); } if (l < 8192) { appendch(c); } } appendch(0); curtoken.tokentype=IT_QUOTED_STRING; return (&curtoken); } if (c == '{') { curtoken.tokennum=0; while ((c=READ()) != '}') { if (!isdigit((int)(unsigned char)c)) { UNREAD(c); curtoken.tokentype=IT_ERROR; return (&curtoken); } curtoken.tokennum = curtoken.tokennum*10 + (c-'0'); } c=READ(); if (c == '\r') { c=READ(); } if (c != '\n') { curtoken.tokentype=IT_ERROR; return (&curtoken); } curtoken.tokentype=IT_LITERAL_STRING_START; return (&curtoken); } l=0; if (c == '\\') { appendch(c); /* Message flag */ c=READ(); } else if (isdigit(c)) { curtoken.tokentype=IT_NUMBER; curtoken.tokennum=0; do { appendch(c); curtoken.tokennum = curtoken.tokennum*10 + (c-'0'); c=READ(); } while (isdigit( (int)(unsigned char)c)); /* Could be stuff like mime.spec, so continue reading. */ } while (c != '\r' && c != '\n' && !isspace((int)(unsigned char)c) && c != '\\' && c != '"' && c != LPAREN_CHAR && c != RPAREN_CHAR && c != '{' && c != '}' && c != LBRACKET_CHAR && c != RBRACKET_CHAR) { curtoken.tokentype=IT_ATOM; if (l < IT_MAX_ATOM_SIZE) { if (touc) c=toupper(c); appendch(c); } else { write_error_exit("max atom size too small"); } c=READ(); } if (l == 0) { curtoken.tokentype=IT_ERROR; return (&curtoken); } appendch(0); UNREAD(c); if (strcmp(curtoken.tokenbuf, "NIL") == 0) curtoken.tokentype=IT_NIL; return (&curtoken); }
struct rfc2045 *fetch_alloc_rfc2045(unsigned long msgnum, FILE *fp) { if (cached_rfc2045p && strcmp(cached_filename, current_maildir_info.msgs[msgnum].filename) == 0) return (cached_rfc2045p); fetch_free_cached(); if ((cached_filename=strdup(current_maildir_info. msgs[msgnum].filename)) == 0) write_error_exit(0); if (fseek(fp, 0L, SEEK_SET) == -1) { write_error_exit(0); return (0); } cached_rfc2045p=rfc2045_fromfp(fp); if (!cached_rfc2045p) { free(cached_filename); cached_filename=0; write_error_exit(0); } return (cached_rfc2045p); }
static int hasnewmsgs(const char *folder) { char *dir=decode_valid_mailbox(folder, 0); char *subdir; if (!dir) return (0); if (is_sharedsubdir(dir)) maildir_shared_sync(dir); subdir=malloc(strlen(dir)+sizeof("/cur")); if (!subdir) write_error_exit(0); strcat(strcpy(subdir, dir), "/new"); if (hasnewmsgs2(subdir)) { free(subdir); free(dir); return (1); } strcat(strcpy(subdir, dir), "/cur"); if (hasnewmsgs2(subdir)) { free(subdir); free(dir); return (1); } free(subdir); free(dir); return (0); }
static void maildir_scan(const char *inbox_dir, const char *inbox_name, struct list_sharable_info *shared_info) { DIR *dirp; struct dirent *de; /* Scan maildir, looking for .subdirectories */ dirp=opendir(inbox_dir && inbox_dir ? inbox_dir:"."); while (dirp && (de=readdir(dirp)) != 0) { char *p; if (de->d_name[0] != '.' || strcmp(de->d_name, "..") == 0) continue; if ((p=malloc(strlen(de->d_name)+strlen(inbox_name)+10)) == 0) /* A bit too much, that's OK */ write_error_exit(0); strcpy(p, inbox_name); if (strcmp(de->d_name, ".")) strcat(p, de->d_name); folder_entry(p, shared_info->pattern, shared_info->flags, shared_info->folders, shared_info->hierarchies); free(p); } if (dirp) closedir(dirp); }
static struct fetchinfo *alloc_headerlist(int oneonly) { struct fetchinfo *list, **listtail, *p; struct imaptoken *tok; list=0; listtail= &list; while ((tok=currenttoken())->tokentype == IT_ATOM || tok->tokentype == IT_QUOTED_STRING || tok->tokentype == IT_NUMBER) { *listtail=p=(struct fetchinfo *)malloc(sizeof(*list)); if (!p) write_error_exit(0); p->next=0; p->name=my_strdup(tok->tokenbuf); p->bodysublist=0; p->bodysection=0; listtail= &p->next; if (oneonly) break; nexttoken_nouc(); } return (list); }
char *my_strdup(const char *s) { char *q=strdup(s); if (!q) write_error_exit("malloc"); return (q); }
void writeqs(const char *s) { size_t i=strlen(s), j; while (i) { for (j=0; j<i; j++) { if ( s[j] == '"' || s[j] == '\\') { writemem(s, j); writemem("\\", 1); writemem(s+j, 1); ++j; s += j; i -= j; j=0; break; } #if 0 if (s[j] == '&') { writemem(s, j); writemem("&-", 2); ++j; s += j; i -= j; j=0; break; } if (s[j] < ' ' || s[j] >= 0x7F) { char *q; writemem(s, j); ++j; s += j; i -= j; for (j=0; j<i; j++) if (s[j] >= ' ' && s[j] < 0x7F) break; q=imap_utf7_encode(s, j); if (!q) write_error_exit(0); writemem("&", 1); writes(q); writemem("-", 1); s += j; i -= j; j=0; break; } #endif } writemem(s, j); s += j; i -= j; } }
static void close_output_file (FILE * fp) { if (fp != stdout) { if (0 != fclose (fp)) write_error_exit (/* msg: errno */ NULL); } else { fflush (fp); } }
struct searchinfo *alloc_search(struct searchinfo **head) { struct searchinfo *si=(struct searchinfo *)malloc(sizeof(**head)); if (si == 0) write_error_exit(0); memset(si, 0, sizeof(*si)); maildir_search_init(&si->sei); si->next= *head; *head=si; return (si); }
static void finalize (void) { const vbi_export_info *xi; xi = vbi_export_info_from_export (ex); if (xi->open_format && NULL == out_file_name_prefix) { if (!vbi_export_stdio (ex, stdout, NULL)) write_error_exit (vbi_export_errstr (ex)); } }
char *get_reflagged_filename(const char *fn, struct imapflags *newflags) { char *p=malloc(strlen(fn)+20); char *q; if (!p) write_error_exit(0); strcpy(p, fn); if ((q=strrchr(p, MDIRSEP[0])) != 0) *q=0; strcat(p, MDIRSEP "2,"); append_flags(p, newflags); return p; }
void msgappends(void (*writefunc)(const char *, size_t), const char *s, size_t l) { size_t i,j; char *q=0; for (i=0; i<l; i++) if (s[i] & 0x80) /* Illegal 8-bit header content */ { char *p=malloc(l+1); if (!p) write_error_exit(0); if (l) memcpy(p, s, l); p[l]=0; /* Assume UTF-8, if not, well, GIGO */ q=rfc2047_encode_str(p, "utf-8", rfc2047_qp_allow_any); free(p); if (!q) write_error_exit(0); s=q; l=strlen(s); } for (i=j=0; i<l; i++) { if (s[i] == '"' || s[i] == '\\') { (*writefunc)(s+j, i-j); (*writefunc)("\\", 1); j=i; } } (*writefunc)(s+j, i-j); if (q) free(q); }
static void alloc_tokenbuf(unsigned l) { if (l >= curtoken.tokenbuf_size) { char *p=curtoken.tokenbuf ? realloc(curtoken.tokenbuf, l + 256): malloc(l + 256); if (!p) write_error_exit("malloc"); curtoken.tokenbuf_size = l+256; curtoken.tokenbuf=p; } }
int storeinfo_init(struct storeinfo *si) { struct imaptoken *t=currenttoken(); const char *p; if (t->tokentype != IT_ATOM) return (-1); si->plusminus=0; si->silent=0; p=t->tokenbuf; if (*p == '+' || *p == '-') si->plusminus= *p++; if (strncmp(p, "FLAGS", 5)) return (-1); p += 5; if (*p) { if (strcmp(p, ".SILENT")) return (-1); si->silent=1; } memset(&si->flags, 0, sizeof(si->flags)); if ((si->keywords=libmail_kwmCreate()) == NULL) write_error_exit(0); t=nexttoken_noparseliteral(); if (t->tokentype == IT_LPAREN) { if (get_flagsAndKeywords(&si->flags, &si->keywords)) { libmail_kwmDestroy(si->keywords); si->keywords=NULL; return (-1); } nexttoken(); } else if (t->tokentype == IT_NIL) nexttoken(); else if (t->tokentype == IT_ATOM) { if (get_flagname(t->tokenbuf, &si->flags)) libmail_kwmSetName(current_maildir_info .keywordList, si->keywords, t->tokenbuf); nexttoken(); } return (0); }
static void list_sharable(const char *n, void *voidp) { struct list_sharable_info *ip=(struct list_sharable_info *)voidp; char *p=malloc(strlen(n)+sizeof("shared.")); if (!p) write_error_exit(0); strcat(strcpy(p, "shared."), n); folder_entry(p, ip->pattern, ip->flags, ip->folders, ip->hierarchies); free(p); }
static void do_param_list(void (*writefunc)(const char *, size_t), struct rfc2045attr *a) { int flag; char *p; flag=0; p="("; for (; a; a=a->next) { (*writefunc)(p, strlen(p)); (*writefunc)("\"", 1); if (a->name) msgappends(writefunc, a->name, strlen(a->name)); (*writefunc)("\" \"", 3); if (a->value) { #if IMAP_CLIENT_BUGS /* NETSCAPE */ char *u, *v, *w; u=strdup(a->value); if (!u) write_error_exit(0); strcpy(u, a->value); for (v=w=u; *v; v++) if (*v != '\\') *w++ = *v; *w=0; msgappends(writefunc, u, strlen(u)); free(u); #else msgappends(writefunc, a->value, strlen(a->value)); #endif } (*writefunc)("\"", 1); flag=1; p=" "; } if (flag) (*writefunc)(")", 1); else (*writefunc)("NIL", 3); }
static int add_hier(struct hierlist **h, const char *s) { struct hierlist *p; for (p= *h; p; p=p->next) if (strcmp(p->hier, s) == 0) return (1); /* Seen this one already */ if ((p=(struct hierlist *) malloc( sizeof(struct hierlist)+1+strlen(s))) == 0) /* HACK!!!! */ write_error_exit(0); p->flag=0; p->hier=(char *)(p+1); strcpy(p->hier, s); p->next= *h; *h=p; return (0); }
const char *maildir_shared_index_file() { static char *filenamep=NULL; if (filenamep == NULL) { const char *p=getenv("IMAP_SHAREDINDEXFILE"); if (p && *p) { const char *q=auth_getoptionenv("sharedgroup"); if (!q) q=""; filenamep=malloc(strlen(p)+strlen(q)+1); if (!filenamep) write_error_exit(0); strcat(strcpy(filenamep, p), q); } } if (filenamep && !shared_index_err_reported) /* Bitch just once */ { struct stat stat_buf; shared_index_err_reported=1; if (stat(filenamep, &stat_buf)) { fprintf(stderr, "ERR: "); perror(filenamep); } } return filenamep; }
static int list_newshared_shortcut(const char *skipped_pattern, struct list_sharable_info *shared_info, const char *acc_pfix, struct maildir_shindex_cache *parentCache, const char *indexfile, const char *subhierarchy) { struct list_newshared_info lni; int rc; struct maildir_shindex_cache *curcache=NULL; lni.acc_pfix=acc_pfix; lni.skipped_pattern=skipped_pattern; lni.shared_info=shared_info; lni.dorecurse=1; /* Try for some common optimization, to avoid expanding the ** entire #shared hierarchy, taking advantage of the cache list. */ for (;;) { const char *p; size_t i; char *q; int eof; if (strcmp(skipped_pattern, "%") == 0) { lni.dorecurse=0; break; } if (strncmp(skipped_pattern, "%" HIERCHS, sizeof("%" HIERCHS)-1) == 0) { curcache=maildir_shared_cache_read(parentCache, indexfile, subhierarchy); if (!curcache) return 0; lni.acc_pfix=acc_pfix; lni.skipped_pattern=skipped_pattern + sizeof("%" HIERCHS)-1; lni.parentCache=curcache; for (i=0; i<curcache->nrecords; i++) { if (i == 0) { curcache->indexfile.startingpos=0; rc=maildir_newshared_nextAt(&curcache->indexfile, &eof, list_newshared_skiplevel, &lni); } else rc=maildir_newshared_next(&curcache->indexfile, &eof, list_newshared_skiplevel, &lni); if (rc || eof) { fprintf(stderr, "ERR:maildir_newshared_next failed: %s\n", strerror(errno)); break; } } return 0; } for (p=skipped_pattern; *p; p++) if (*p == HIERCH || ((lni.shared_info->flags & LIST_CHECK1FOLDER) == 0 && (*p == '*' || *p == '%'))) break; if (*p && *p != HIERCH) break; curcache=maildir_shared_cache_read(parentCache, indexfile, subhierarchy); if (!curcache) return 0; for (i=0; i < curcache->nrecords; i++) { char *n=maildir_info_imapmunge(curcache->records[i] .name); if (!n) write_error_exit(0); if (strlen(n) == p-skipped_pattern && strncmp(n, skipped_pattern, p-skipped_pattern) == 0) { free(n); break; } free(n); } if (i >= curcache->nrecords) /* not found */ return 0; if (*p) ++p; q=malloc(strlen(acc_pfix)+(p-skipped_pattern)+1); if (!q) { write_error_exit(0); } strcpy(q, acc_pfix); strncat(q, skipped_pattern, p-skipped_pattern); lni.acc_pfix=q; lni.skipped_pattern=p; lni.parentCache=curcache; curcache->indexfile.startingpos=curcache->records[i].offset; rc=maildir_newshared_nextAt(&curcache->indexfile, &eof, list_newshared_skipcb, &lni); free(q); return rc; } if (!indexfile) indexfile=maildir_shared_index_file(); rc=maildir_newshared_enum(indexfile, list_newshared_cb, &lni); return rc; }
static void do_export (vbi_pgno pgno, vbi_subno subno) { vbi_page page; vbi_bool success; if (option_delay > 1) { --option_delay; return; } success = vbi_fetch_vt_page (vbi, &page, pgno, subno, VBI_WST_LEVEL_3p5, /* n_rows */ 25, /* navigation */ TRUE); if (!success) { /* Shouldn't happen. */ error_exit (_("Unknown error.")); } if (option_dump_pg) { page_dump (&page); } switch (option_target) { char *file_name; void *buffer; void *buffer2; FILE *fp; size_t size; ssize_t ssize; case 1: buffer = malloc (1 << 20); if (NULL == buffer) no_mem_exit (); ssize = vbi_export_mem (ex, buffer, 1 << 20, &page); success = (ssize >= 0); if (success) { ssize_t ssize2; fp = open_output_file (pgno, subno); if (1 != fwrite (buffer, ssize, 1, fp)) write_error_exit (/* msg: errno */ NULL); close_output_file (fp); /* Test. */ ssize2 = vbi_export_mem (ex, buffer, 0, &page); assert (ssize == ssize2); assert (ssize > 0); ssize2 = vbi_export_mem (ex, buffer, ssize - 1, &page); assert (ssize == ssize2); } free (buffer); break; case 2: buffer = NULL; buffer2 = vbi_export_alloc (ex, &buffer, &size, &page); /* Test. */ assert (buffer == buffer2); success = (NULL != buffer); if (success) { fp = open_output_file (pgno, subno); if (1 != fwrite (buffer, size, 1, fp)) write_error_exit (/* msg: errno */ NULL); close_output_file (fp); free (buffer); } break; case 3: /* This is the default target. The other cases are only implemented for tests and will be removed when I wrote proper unit tests. */ fp = open_output_file (pgno, subno); success = vbi_export_stdio (ex, fp, &page); close_output_file (fp); break; case 5: file_name = output_file_name (pgno, subno); success = vbi_export_file (ex, file_name, &page); free (file_name); break; default: error_exit ("Invalid target %u.", option_target); break; } if (!success) { error_exit (_("Export of page %x failed: %s"), pgno, vbi_export_errstr (ex)); } vbi_unref_page (&page); }
int reflag_filename(struct imapscanmessageinfo *mi, struct imapflags *flags, int fd) { char *p, *q, *r; int rc=0; struct imapflags old_flags; struct stat stat_buf; get_message_flags(mi, 0, &old_flags); p=get_reflagged_filename(mi->filename, flags); q=malloc(strlen(current_mailbox)+strlen(mi->filename)+sizeof("/cur/")); r=malloc(strlen(current_mailbox)+strlen(p)+sizeof("/cur/")); if (!q || !r) write_error_exit(0); strcat(strcat(strcpy(q, current_mailbox), "/cur/"), mi->filename); strcat(strcat(strcpy(r, current_mailbox), "/cur/"), p); if (strcmp(q, r)) { if (maildirquota_countfolder(current_mailbox) && old_flags.deleted != flags->deleted && fstat(fd, &stat_buf) == 0) { struct maildirsize quotainfo; int64_t nbytes; unsigned long unbytes; int nmsgs=1; if (maildir_parsequota(mi->filename, &unbytes) == 0) nbytes=unbytes; else nbytes=stat_buf.st_size; if ( flags->deleted ) { nbytes= -nbytes; nmsgs= -nmsgs; } if ( maildir_quota_delundel_start(current_mailbox, "ainfo, nbytes, nmsgs)) rc= -1; else maildir_quota_delundel_end("ainfo, nbytes, nmsgs); } if (rc == 0) rename(q, r); #if SMAP snapshot_needed(); #endif } free(q); free(r); free(mi->filename); mi->filename=p; #if 0 if (is_sharedsubdir(current_mailbox)) maildir_shared_updateflags(current_mailbox, p); #endif return (rc); }
int do_imap_command(const char *tag) { struct imaptoken *curtoken=nexttoken(); char authservice[40]; #if SMAP if (strcmp(tag, "\\SMAP1") == 0) { const char *p=getenv("SMAP_CAPABILITY"); if (p && *p) putenv("PROTOCOL=SMAP1"); else return -1; } #endif courier_authdebug_login( 1, "command=%s", curtoken->tokenbuf ); if (strcmp(curtoken->tokenbuf, "LOGOUT") == 0) { if (nexttoken()->tokentype != IT_EOL) return (-1); writes("* BYE Courier-IMAP server shutting down\r\n"); cmdsuccess(tag, "LOGOUT completed\r\n"); writeflush(); fprintf(stderr, "INFO: LOGOUT, ip=[%s], rcvd=%lu, sent=%lu\n", getenv("TCPREMOTEIP"), bytes_received_count, bytes_sent_count); exit(0); } if (strcmp(curtoken->tokenbuf, "NOOP") == 0) { if (nexttoken()->tokentype != IT_EOL) return (-1); cmdsuccess(tag, "NOOP completed\r\n"); return (0); } if (strcmp(curtoken->tokenbuf, "CAPABILITY") == 0) { if (nexttoken()->tokentype != IT_EOL) return (-1); writes("* CAPABILITY "); imapcapability(); writes("\r\n"); cmdsuccess(tag, "CAPABILITY completed\r\n"); return (0); } if (strcmp(curtoken->tokenbuf, "STARTTLS") == 0) { if (!have_starttls()) return (-1); if (starttls(tag)) return (-2); putenv("IMAP_STARTTLS=NO"); putenv("IMAP_TLS_REQUIRED=0"); putenv("IMAP_TLS=1"); return (0); } if (strcmp(curtoken->tokenbuf, "LOGIN") == 0) { struct imaptoken *tok=nexttoken_nouc(); char *userid; char *passwd; const char *p; int rc; if (have_starttls() && tlsrequired()) /* Not yet */ { cmdfail(tag, "STARTTLS required\r\n"); return (0); } switch (tok->tokentype) { case IT_ATOM: case IT_NUMBER: case IT_QUOTED_STRING: break; default: return (-1); } userid=strdup(tok->tokenbuf); if (!userid) write_error_exit(0); tok=nexttoken_nouc_okbracket(); switch (tok->tokentype) { case IT_ATOM: case IT_NUMBER: case IT_QUOTED_STRING: break; default: free(userid); return (-1); } passwd=my_strdup(tok->tokenbuf); if (nexttoken()->tokentype != IT_EOL) { free(userid); free(passwd); return (-1); } strcat(strcpy(authservice, "AUTHSERVICE"), getenv("TCPLOCALPORT")); p=getenv(authservice); if (!p || !*p) p="imap"; rc=auth_login(p, userid, passwd, login_callback, (void *)tag); courier_safe_printf("INFO: LOGIN FAILED, user=%s, ip=[%s]", userid, getenv("TCPREMOTEIP")); free(userid); free(passwd); if (rc > 0) { perror("ERR: authentication error"); writes("* BYE Temporary problem, please try again later\r\n"); writeflush(); exit(1); } sleep(5); cmdfail(tag, "Login failed.\r\n"); return (0); } if (strcmp(curtoken->tokenbuf, "AUTHENTICATE") == 0) { char method[32]; int rc; if (have_starttls() && tlsrequired()) /* Not yet */ { cmdfail(tag, "STARTTLS required\r\n"); return (0); } rc=authenticate(tag, method, sizeof(method)); courier_safe_printf("INFO: LOGIN FAILED, method=%s, ip=[%s]", method, getenv("TCPREMOTEIP")); if (rc > 0) { perror("ERR: authentication error"); writes("* BYE Temporary problem, please try again later\r\n"); writeflush(); exit(1); } sleep(5); cmdfail(tag, "Login failed.\r\n"); writeflush(); return (-2); } return (-1); }
struct fetchinfo *fetchinfo_alloc(int oneonly) { struct fetchinfo *list, **listtail, *p; struct imaptoken *tok; list=0; listtail= &list; while ((tok=currenttoken())->tokentype == IT_ATOM) { if (oneonly && list) break; *listtail=p=(struct fetchinfo *)malloc(sizeof(*list)); if (!p) write_error_exit(0); p->next=0; p->name=my_strdup(tok->tokenbuf); p->bodysection=0; p->bodysublist=0; p->ispartial=0; listtail= &p->next; if (strcmp(p->name, "ALL") == 0 || strcmp(p->name, "BODYSTRUCTURE") == 0 || strcmp(p->name, "ENVELOPE") == 0 || strcmp(p->name, "FLAGS") == 0 || strcmp(p->name, "FAST") == 0 || strcmp(p->name, "FULL") == 0 || strcmp(p->name, "INTERNALDATE") == 0 || strcmp(p->name, "RFC822") == 0 || strcmp(p->name, "RFC822.HEADER") == 0 || strcmp(p->name, "RFC822.SIZE") == 0 || strcmp(p->name, "RFC822.TEXT") == 0 || strcmp(p->name, "UID") == 0) { nexttoken(); continue; } if (strcmp(p->name, "BODY") && strcmp(p->name, "BODY.PEEK")) break; if (nexttoken()->tokentype != IT_LBRACKET) continue; /* Parse BODY[ ... ] */ if ((tok=nexttoken())->tokentype != IT_RBRACKET) { char *s; if ( (tok->tokentype != IT_ATOM && tok->tokentype != IT_NUMBER) || !(s=good_section(tok->tokenbuf))) { fetchinfo_free(list); return (0); } p->bodysection=my_strdup(tok->tokenbuf); if (strcmp(s, "HEADER.FIELDS") == 0 || strcmp(s, "HEADER.FIELDS.NOT") == 0) { /* Must be followed by header list */ if ((tok=nexttoken_nouc())->tokentype != IT_LPAREN) { p->bodysublist=alloc_headerlist(1); if (p->bodysublist == 0) { fetchinfo_free(list); return (0); } } else { nexttoken_nouc(); p->bodysublist=alloc_headerlist(0); if ( currenttoken()->tokentype != IT_RPAREN) { fetchinfo_free(list); return (0); } } } tok=nexttoken(); } else p->bodysection=my_strdup(""); if (tok->tokentype != IT_RBRACKET) { fetchinfo_free(list); return (0); } tok=nexttoken(); if (tok->tokentype == IT_ATOM && tok->tokenbuf[0] == '<' && tok->tokenbuf[strlen(tok->tokenbuf)-1] == '>' && (p->ispartial=sscanf(tok->tokenbuf+1, "%lu.%lu", &p->partialstart, &p->partialend)) > 0) nexttoken(); } return (list); }
int do_store(unsigned long n, int byuid, void *voidptr) { struct storeinfo *si=(struct storeinfo *)voidptr; int fd; struct imapflags new_flags, old_flags; int changedKeywords; struct libmail_kwMessageEntry *kme; int kwAllowed=1; --n; fd=imapscan_openfile(current_mailbox, ¤t_maildir_info, n); if (fd < 0) return (0); changedKeywords=0; get_message_flags(current_maildir_info.msgs+n, 0, &new_flags); old_flags=new_flags; if (current_mailbox_acl) { if (strchr(current_mailbox_acl, ACL_WRITE[0]) == NULL) kwAllowed=0; } if (si->plusminus == '+') { if (si->flags.drafts) new_flags.drafts=1; if (si->flags.seen) new_flags.seen=1; if (si->flags.answered) new_flags.answered=1; if (si->flags.deleted) new_flags.deleted=1; if (si->flags.flagged) new_flags.flagged=1; for (kme=si->keywords ? si->keywords->firstEntry:NULL; kme; kme=kme->next) { int rc; if (!kwAllowed) { current_maildir_info.msgs[n].changedflags=1; continue; } imapscan_createKeyword(¤t_maildir_info, n); if ((rc=libmail_kwmSet(current_maildir_info.msgs[n] .keywordMsg, kme->libmail_keywordEntryPtr)) < 0) { write_error_exit(0); return 0; } if (rc == 0) { if (fastkeywords()) changedKeywords=1; current_maildir_info.msgs[n].changedflags=1; } } } else if (si->plusminus == '-') { if (si->flags.drafts) new_flags.drafts=0; if (si->flags.seen) new_flags.seen=0; if (si->flags.answered) new_flags.answered=0; if (si->flags.deleted) new_flags.deleted=0; if (si->flags.flagged) new_flags.flagged=0; if (current_maildir_info.msgs[n].keywordMsg && kwAllowed) for (kme=si->keywords ? si->keywords->firstEntry:NULL; kme; kme=kme->next) { if (!kwAllowed) { current_maildir_info.msgs[n] .changedflags=1; continue; } if (libmail_kwmClear(current_maildir_info.msgs[n] .keywordMsg, kme->libmail_keywordEntryPtr)==0) { if (fastkeywords()) changedKeywords=1; current_maildir_info.msgs[n] .changedflags=1; } } if (current_maildir_info.msgs[n].keywordMsg && !current_maildir_info.msgs[n].keywordMsg->firstEntry) { libmail_kwmDestroy(current_maildir_info.msgs[n] .keywordMsg); current_maildir_info.msgs[n].keywordMsg=NULL; } } else { struct libmail_kwMessage *kw; new_flags=si->flags; kw=current_maildir_info.msgs[n].keywordMsg; if (kw && kw->firstEntry == NULL) kw=NULL; if (si->keywords && si->keywords->firstEntry == NULL) si->keywords=NULL; if ((si->keywords && !kw) || (!si->keywords && kw) || (si->keywords && kw && libmail_kwmCmp(si->keywords, kw))) { if (kwAllowed) { kw=current_maildir_info.msgs[n].keywordMsg; if (kw) libmail_kwmDestroy(kw); current_maildir_info.msgs[n].keywordMsg=NULL; if (si->keywords && si->keywords->firstEntry) { struct libmail_kwMessageEntry *kme; kw=imapscan_createKeyword(¤t_maildir_info, n); for (kme=si->keywords->lastEntry; kme; kme=kme->prev) if (libmail_kwmSet(kw, kme->libmail_keywordEntryPtr) < 0) write_error_exit(0); current_maildir_info.msgs[n].keywordMsg=kw; } } changedKeywords=1; } } if (current_mailbox_acl) { if (strchr(current_mailbox_acl, ACL_WRITE[0]) == NULL) { new_flags.drafts=old_flags.drafts; new_flags.answered=old_flags.answered; new_flags.flagged=old_flags.flagged; } if (strchr(current_mailbox_acl, ACL_SEEN[0]) == NULL) { new_flags.seen=old_flags.seen; } if (strchr(current_mailbox_acl, ACL_DELETEMSGS[0]) == NULL) { new_flags.deleted=old_flags.deleted; } } if (changedKeywords) { current_maildir_info.msgs[n].changedflags=1; if (imapscan_updateKeywords(current_maildir_info.msgs[n] .filename, current_maildir_info.msgs[n] .keywordMsg)) { close(fd); return -1; } } if (reflag_filename(current_maildir_info.msgs+n, &new_flags, fd)) { close(fd); return (-1); } close(fd); if (si->silent) current_maildir_info.msgs[n].changedflags=0; else { #if SMAP /* SMAP flag notification is handled elsewhere */ if (!smapflag) #endif { if (byuid) fetchflags_byuid(n); else fetchflags(n); } } return (0); }
FILE *open_cached_fp(unsigned long msgnum) { int fd; if (cached_fp && strcmp(cached_fp_filename, current_maildir_info.msgs[msgnum].filename) == 0) return (cached_fp); if (cached_fp) { fclose(cached_fp); free(cached_fp_filename); cached_fp_filename=0; cached_fp=0; } fd=imapscan_openfile(current_mailbox, ¤t_maildir_info, msgnum); if (fd < 0 || (cached_fp=fdopen(fd, "r")) == 0) { if (fd >= 0) close(fd); if ((cached_fp=tmpfile()) != 0) { fprintf(cached_fp, unavailable); if (fseek(cached_fp, 0L, SEEK_SET) < 0 || ferror(cached_fp)) { fclose(cached_fp); cached_fp=0; } } if (cached_fp == 0) { fprintf(stderr, "ERR: %s: %s\n", getenv("AUTHENTICATED"), #if HAVE_STRERROR strerror(errno) #else "error" #endif ); fflush(stderr); _exit(1); } } if ((cached_fp_filename=strdup(current_maildir_info. msgs[msgnum].filename)) == 0) { fclose(cached_fp); cached_fp=0; write_error_exit(0); } cached_base_offset=0; cached_virtual_offset=0; cached_phys_offset=0; return (cached_fp); }
static struct searchinfo *alloc_search_key(struct searchinfo **head) { struct imaptoken *t=currenttoken(); struct searchinfo *si; const char *keyword; if (t->tokentype == IT_LPAREN) { nexttoken(); if ((si=alloc_search_andlist(head)) == 0 || currenttoken()->tokentype != IT_RPAREN) return (0); nexttoken(); return (si); } if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER) return (0); keyword=t->tokenbuf; if (strcmp(keyword, "ALL") == 0) { struct searchinfo *si; (si=alloc_search(head))->type=search_all; nexttoken(); return (si); } if (strcmp(keyword, "OR") == 0) { struct searchinfo *si; si=alloc_search(head); si->type=search_or; nexttoken(); if ((si->a=alloc_search_notkey(head)) == 0 || (si->b=alloc_search_notkey(head)) == 0) return (0); return (si); } if (strcmp(keyword, "HEADER") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_header; t=nexttoken_okbracket(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->cs=strdup(t->tokenbuf); if (!si->cs) write_error_exit(0); t=nexttoken_okbracket(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "BCC") == 0 || strcmp(keyword, "CC") == 0 || strcmp(keyword, "FROM") == 0 || strcmp(keyword, "TO") == 0 || strcmp(keyword, "SUBJECT") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_header; si->cs=my_strdup(keyword); t=nexttoken_okbracket(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "BEFORE") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_before; t=nexttoken(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "BODY") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_body; t=nexttoken_okbracket(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "LARGER") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_larger; t=nexttoken(); if (t->tokentype != IT_NUMBER) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "ON") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_on; t=nexttoken(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "SENTBEFORE") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_sentbefore; t=nexttoken(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "SENTON") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_senton; t=nexttoken(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(keyword); nexttoken(); return (si); } if (strcmp(keyword, "SENTSINCE") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_sentsince; t=nexttoken(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "SINCE") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_since; t=nexttoken(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "SMALLER") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_smaller; t=nexttoken(); if (t->tokentype != IT_NUMBER) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "TEXT") == 0) { struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_text; t=nexttoken_okbracket(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "UID") == 0) { struct searchinfo *si; struct imaptoken *t; si=alloc_search(head); si->type=search_uid; t=nexttoken(); if (!ismsgset(t)) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } if (strcmp(keyword, "KEYWORD") == 0 || strcmp(keyword, "UNKEYWORD") == 0) { int isnot= *keyword == 'U'; struct imaptoken *t; struct searchinfo *si; si=alloc_search(head); si->type=search_msgkeyword; t=nexttoken_okbracket(); if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER && t->tokentype != IT_QUOTED_STRING) return (0); si->as=my_strdup(t->tokenbuf); nexttoken(); if (isnot) { struct searchinfo *si2=alloc_search(head); si2->type=search_not; si2->a=si; si=si2; } return (si); } if (strcmp(keyword, "ANSWERED") == 0 || strcmp(keyword, "DELETED") == 0 || strcmp(keyword, "DRAFT") == 0 || strcmp(keyword, "FLAGGED") == 0 || strcmp(keyword, "RECENT") == 0 || strcmp(keyword, "SEEN") == 0) { struct searchinfo *si; si=alloc_search(head); si->type=search_msgflag; if ((si->as=malloc(strlen(keyword)+2)) == 0) write_error_exit(0); si->as[0]='\\'; strcpy(si->as+1, keyword); nexttoken(); return (si); } if (strcmp(keyword, "UNANSWERED") == 0 || strcmp(keyword, "UNDELETED") == 0 || strcmp(keyword, "UNDRAFT") == 0 || strcmp(keyword, "UNFLAGGED") == 0 || strcmp(keyword, "UNSEEN") == 0) { struct searchinfo *si; struct searchinfo *si2; si=alloc_search(head); si->type=search_msgflag; if ((si->as=malloc(strlen(keyword))) == 0) write_error_exit(0); si->as[0]='\\'; strcpy(si->as+1, keyword+2); nexttoken(); si2=alloc_search(head); si2->type=search_not; si2->a=si; return (si2); } if (strcmp(keyword, "NEW") == 0) { struct searchinfo *si, *si2; si=alloc_search(head); si->type=search_and; si2=si->a=alloc_search(head); si2->type=search_msgflag; si2->as=my_strdup("\\RECENT"); si2=si->b=alloc_search(head); si2->type=search_not; si2=si2->a=alloc_search(head); si2->type=search_msgflag; si2->as=my_strdup("\\SEEN"); nexttoken(); return (si); } if (strcmp(keyword, "OLD") == 0) { struct searchinfo *si, *si2; si=alloc_search(head); si->type=search_not; si2=si->a=alloc_search(head); si2->type=search_msgflag; si2->as=my_strdup("\\RECENT"); nexttoken(); return (si); } if (ismsgset(t)) { si=alloc_search(head); si->type=search_messageset; si->as=my_strdup(t->tokenbuf); nexttoken(); return (si); } return (0); }
static int list_newshared_cb(struct maildir_newshared_enum_cb *cb) { const char *name=cb->name; const char *homedir=cb->homedir; const char *maildir=cb->maildir; struct list_newshared_info *lni= (struct list_newshared_info *)cb->cb_arg; char *n=maildir_info_imapmunge(name); int rc; if (!n) write_error_exit(0); if (homedir == NULL) { struct list_newshared_info new_lni= *lni; char *new_pfix=malloc(strlen(lni->acc_pfix)+ strlen(n)+2); if (!new_pfix) write_error_exit(0); strcat(strcpy(new_pfix, lni->acc_pfix), n); free(n); n=new_pfix; new_lni.acc_pfix=n; add_hier(lni->shared_info->hierarchies, n); hier_entry(n, lni->shared_info->hierarchies); strcat(n, hierchs); rc=lni->dorecurse ? maildir_newshared_enum(maildir, list_newshared_cb, &new_lni):0; } else { char *new_pfix; struct stat stat_buf; new_pfix=maildir_location(homedir, maildir); if (stat(new_pfix, &stat_buf) < 0 || /* maildir inaccessible, perhaps another server? */ (stat_buf.st_dev == homedir_dev && stat_buf.st_ino == homedir_ino)) /* Exclude ourselves from the shared list */ { free(new_pfix); free(n); return 0; } free(new_pfix); new_pfix=malloc(strlen(lni->acc_pfix)+ strlen(n)+1); if (!new_pfix) write_error_exit(0); strcat(strcpy(new_pfix, lni->acc_pfix), n); free(n); n=new_pfix; new_pfix=malloc(strlen(homedir)+strlen(maildir)+2); if (!new_pfix) write_error_exit(0); if (*maildir == '/') strcpy(new_pfix, maildir); else strcat(strcat(strcpy(new_pfix, homedir), "/"), maildir); /* if (lni->dorecurse) */ maildir_scan(new_pfix, n, lni->shared_info); #if 0 else { folder_entry(n, lni->shared_info->pattern, lni->shared_info->flags, lni->shared_info->folders, lni->shared_info->hierarchies); } #endif free(new_pfix); rc=0; }
static void do_export (vbi_pgno pgno, vbi_subno subno, double timestamp) { vbi_page *pg; vbi_bool success; if (option_delay > 1) { --option_delay; return; } if (pgno >= 0x100) { if (0 != option_override_cs) { pg = vbi_decoder_get_page (vbi, NULL /* current network */, pgno, subno, VBI_HEADER_ONLY, option_header_only, VBI_PADDING, option_padding, VBI_PANELS, option_panels, VBI_NAVIGATION, option_navigation, VBI_HYPERLINKS, option_hyperlinks, VBI_PDC_LINKS, option_pdc_links, VBI_WST_LEVEL, VBI_WST_LEVEL_3p5, VBI_OVERRIDE_CHARSET_0, option_override_cs, VBI_END); } else { pg = vbi_decoder_get_page (vbi, NULL /* current network */, pgno, subno, VBI_HEADER_ONLY, option_header_only, VBI_PADDING, option_padding, VBI_PANELS, option_panels, VBI_NAVIGATION, option_navigation, VBI_HYPERLINKS, option_hyperlinks, VBI_PDC_LINKS, option_pdc_links, VBI_WST_LEVEL, VBI_WST_LEVEL_3p5, VBI_DEFAULT_CHARSET_0, option_default_cs, VBI_END); } } else { pg = vbi_decoder_get_page (vbi, NULL /* current network */, pgno, subno, VBI_PADDING, option_padding, VBI_DEFAULT_FOREGROUND, option_default_fg, VBI_DEFAULT_BACKGROUND, option_default_bg, VBI_ROW_CHANGE, option_row_update, VBI_END); } assert (NULL != pg); if (option_dump_pg) { page_dump (pg); } switch (option_target) { char *file_name; void *buffer; void *buffer2; FILE *fp; size_t size; ssize_t ssize; case 1: buffer = malloc (1 << 20); if (NULL == buffer) no_mem_exit (); ssize = vbi_export_mem (ex, buffer, 1 << 20, pg); success = (ssize >= 0); if (success) { ssize_t ssize2; fp = open_output_file (pgno, subno); if (1 != fwrite (buffer, ssize, 1, fp)) write_error_exit (/* msg: errno */ NULL); close_output_file (fp); /* Test. */ ssize2 = vbi_export_mem (ex, buffer, 0, pg); assert (ssize == ssize2); assert (ssize > 0); ssize2 = vbi_export_mem (ex, buffer, ssize - 1, pg); assert (ssize == ssize2); } free (buffer); break; case 2: buffer = NULL; buffer2 = vbi_export_alloc (ex, &buffer, &size, pg); /* Test. */ assert (buffer == buffer2); success = (NULL != buffer); if (success) { fp = open_output_file (pgno, subno); if (1 != fwrite (buffer, size, 1, fp)) write_error_exit (/* msg: errno */ NULL); close_output_file (fp); free (buffer); } break; case 3: /* This is the default target. The other cases are only implemented for tests and will be removed when I wrote proper unit tests. */ fp = open_output_file (pgno, subno); /* For proper timing of subtitles. */ vbi_export_set_timestamp (ex, timestamp); success = vbi_export_stdio (ex, fp, pg); close_output_file (fp); break; case 5: file_name = output_file_name (pgno, subno); success = vbi_export_file (ex, file_name, pg); free (file_name); break; default: error_exit ("Invalid target %u.", option_target); break; } if (!success) { error_exit (_("Export of page %x failed: %s"), pgno, vbi_export_errstr (ex)); } if (option_pdc_enum) { pdc_dump (pg); } vbi_page_delete (pg); pg = NULL; }