/* * This routine does RfC3676 space stuffing since it's a MUST. * Space stuffing means that we have to add leading spaces to * certain lines: * - lines starting with a space * - lines starting with 'From ' * This routine is only called once right after editing the * initial message so it's up to the user to take care of stuffing * when editing the message several times before actually sending it * * This is more or less a hack as it replaces the message's content with * a freshly created copy in a tempfile and modifies the file's mtime * so we don't trigger code paths watching for mtime changes */ void rfc3676_space_stuff (HEADER* hdr) { #if DEBUG int lc = 0; size_t len = 0; unsigned char c = '\0'; #endif FILE *in = NULL, *out = NULL; char buf[LONG_STRING]; char tmpfile[_POSIX_PATH_MAX]; if (!hdr || !hdr->content || !hdr->content->filename) return; dprint (2, (debugfile, "f=f: postprocess %s\n", hdr->content->filename)); if ((in = safe_fopen (hdr->content->filename, "r")) == NULL) return; mutt_mktemp (tmpfile, sizeof (tmpfile)); if ((out = safe_fopen (tmpfile, "w+")) == NULL) { safe_fclose (&in); return; } while (fgets (buf, sizeof (buf), in)) { if (ascii_strncmp ("From ", buf, 5) == 0 || buf[0] == ' ') { fputc (' ', out); #if DEBUG lc++; len = mutt_strlen (buf); if (len > 0) { c = buf[len-1]; buf[len-1] = '\0'; } dprint (4, (debugfile, "f=f: line %d needs space-stuffing: '%s'\n", lc, buf)); if (len > 0) buf[len-1] = c; #endif } fputs (buf, out); } safe_fclose (&in); safe_fclose (&out); mutt_set_mtime (hdr->content->filename, tmpfile); unlink (hdr->content->filename); mutt_str_replace (&hdr->content->filename, tmpfile); }
static int browse_add_list_result (IMAP_DATA* idata, const char* cmd, struct browser_state* state, short isparent) { char *name; int noselect; int noinferiors; IMAP_MBOX mx; if (imap_parse_path (state->folder, &mx)) { dprint (2, (debugfile, "browse_add_list_result: current folder %s makes no sense\n", state->folder)); return -1; } imap_cmd_start (idata, cmd); do { if (imap_parse_list_response(idata, &name, &noselect, &noinferiors, &idata->delim) != 0) { FREE (&mx.mbox); return -1; } if (name) { /* Let a parent folder never be selectable for navigation */ if (isparent) noselect = 1; /* prune current folder from output */ if (isparent || mutt_strncmp (name, mx.mbox, strlen (name))) imap_add_folder (idata->delim, name, noselect, noinferiors, state, isparent); } } while ((ascii_strncmp (idata->cmd.buf, idata->cmd.seq, SEQLEN) != 0)); FREE (&mx.mbox); return 0; }
/* Check which namespaces have contents */ static int browse_verify_namespace (IMAP_DATA* idata, IMAP_NAMESPACE_INFO *nsi, int nns) { char buf[LONG_STRING]; int i = 0; char *name; char delim; for (i = 0; i < nns; i++, nsi++) { /* Cyrus gives back nothing if the % isn't added. This may return lots * of data in some cases, I guess, but I currently feel that's better * than invisible namespaces */ if (nsi->delim) snprintf (buf, sizeof (buf), "%s \"\" \"%s%c%%\"", option (OPTIMAPLSUB) ? "LSUB" : "LIST", nsi->prefix, nsi->delim); else snprintf (buf, sizeof (buf), "%s \"\" \"%s%%\"", option (OPTIMAPLSUB) ? "LSUB" : "LIST", nsi->prefix); imap_cmd_start (idata, buf); nsi->listable = 0; nsi->home_namespace = 0; do { if (imap_parse_list_response(idata, &name, &nsi->noselect, &nsi->noinferiors, &delim) != 0) return -1; nsi->listable |= (name != NULL); } while ((ascii_strncmp (idata->cmd.buf, idata->cmd.seq, SEQLEN) != 0)); } return 0; }
/* imap_auth_sasl: Default authenticator if available. */ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method) { sasl_conn_t* saslconn; sasl_interact_t* interaction = NULL; int rc, irc; char buf[HUGE_STRING]; const char* mech; const char *pc = NULL; unsigned int len, olen; unsigned char client_start; if (mutt_sasl_client_new (idata->conn, &saslconn) < 0) { dprint (1, (debugfile, "imap_auth_sasl: Error allocating SASL connection.\n")); return IMAP_AUTH_FAILURE; } rc = SASL_FAIL; /* If the user hasn't specified a method, use any available */ if (!method) { method = idata->capstr; /* hack for SASL ANONYMOUS support: * 1. Fetch username. If it's "" or "anonymous" then * 2. attempt sasl_client_start with only "AUTH=ANONYMOUS" capability * 3. if sasl_client_start fails, fall through... */ if (mutt_account_getuser (&idata->conn->account)) return IMAP_AUTH_FAILURE; if (mutt_bit_isset (idata->capabilities, AUTH_ANON) && (!idata->conn->account.user[0] || !ascii_strncmp (idata->conn->account.user, "anonymous", 9))) rc = sasl_client_start (saslconn, "AUTH=ANONYMOUS", NULL, &pc, &olen, &mech); } else if (!ascii_strcasecmp ("login", method) && !strstr (NONULL (idata->capstr), "AUTH=LOGIN")) /* do not use SASL login for regular IMAP login (#3556) */ return IMAP_AUTH_UNAVAIL; if (rc != SASL_OK && rc != SASL_CONTINUE) do { rc = sasl_client_start (saslconn, method, &interaction, &pc, &olen, &mech); if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); client_start = (olen > 0); if (rc != SASL_OK && rc != SASL_CONTINUE) { if (method) dprint (2, (debugfile, "imap_auth_sasl: %s unavailable\n", method)); else dprint (1, (debugfile, "imap_auth_sasl: Failure starting authentication exchange. No shared mechanisms?\n")); /* SASL doesn't support LOGIN, so fall back */ return IMAP_AUTH_UNAVAIL; } mutt_message (_("Authenticating (%s)..."), mech); snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech); if (mutt_bit_isset (idata->capabilities, SASL_IR) && client_start) { len = mutt_strlen (buf); buf[len++] = ' '; if (sasl_encode64 (pc, olen, buf + len, sizeof (buf) - len, &olen) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n")); goto bail; } client_start = olen = 0; } imap_cmd_start (idata, buf); irc = IMAP_CMD_CONTINUE; /* looping protocol */ while (rc == SASL_CONTINUE || olen > 0) { do irc = imap_cmd_step (idata); while (irc == IMAP_CMD_CONTINUE); if (irc == IMAP_CMD_BAD || irc == IMAP_CMD_NO) goto bail; if (irc == IMAP_CMD_RESPOND) { /* Exchange incorrectly returns +\r\n instead of + \r\n */ if (idata->buf[1] == '\0') { buf[0] = '\0'; len = 0; } else if (sasl_decode64 (idata->buf+2, strlen (idata->buf+2), buf, LONG_STRING-1, &len) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n")); goto bail; } } /* client-start is only available with the SASL-IR extension, but * SASL 2.1 seems to want to use it regardless, at least for DIGEST * fast reauth. Override if the server sent an initial continuation */ if (!client_start || buf[0]) { do { rc = sasl_client_step (saslconn, buf, len, &interaction, &pc, &olen); if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); } else client_start = 0; /* send out response, or line break if none needed */ if (olen) { if (sasl_encode64 (pc, olen, buf, sizeof (buf), &olen) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n")); goto bail; } } if (irc == IMAP_CMD_RESPOND) { strfcpy (buf + olen, "\r\n", sizeof (buf) - olen); mutt_socket_write (idata->conn, buf); } /* If SASL has errored out, send an abort string to the server */ if (rc < 0) { mutt_socket_write (idata->conn, "*\r\n"); dprint (1, (debugfile, "imap_auth_sasl: sasl_client_step error %d\n",rc)); } olen = 0; } while (irc != IMAP_CMD_OK) if ((irc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; if (rc != SASL_OK) goto bail; if (imap_code (idata->buf)) { mutt_sasl_setup_conn (idata->conn, saslconn); return IMAP_AUTH_SUCCESS; } bail: sasl_dispose (&saslconn); if (method) { dprint (2, (debugfile, "imap_auth_sasl: %s failed\n", method)); return IMAP_AUTH_UNAVAIL; } mutt_error _("SASL authentication failed."); mutt_sleep(2); return IMAP_AUTH_FAILURE; }
/* imap_parse_path: given an IMAP mailbox name, return host, port * and a path IMAP servers will recognise. * mx.mbox is malloc'd, caller must free it */ int imap_parse_path (const char* path, IMAP_MBOX* mx) { static unsigned short ImapPort = 0; static unsigned short ImapsPort = 0; struct servent* service; char tmp[128]; ciss_url_t url; char *c; int n; if (!ImapPort) { service = getservbyname ("imap", "tcp"); if (service) ImapPort = ntohs (service->s_port); else ImapPort = IMAP_PORT; dprint (3, (debugfile, "Using default IMAP port %d\n", ImapPort)); } if (!ImapsPort) { service = getservbyname ("imaps", "tcp"); if (service) ImapsPort = ntohs (service->s_port); else ImapsPort = IMAP_SSL_PORT; dprint (3, (debugfile, "Using default IMAPS port %d\n", ImapsPort)); } /* Defaults */ memset(&mx->account, 0, sizeof(mx->account)); mx->account.port = ImapPort; mx->account.type = M_ACCT_TYPE_IMAP; c = safe_strdup (path); url_parse_ciss (&url, c); if (url.scheme == U_IMAP || url.scheme == U_IMAPS) { if (mutt_account_fromurl (&mx->account, &url) < 0 || !*mx->account.host) { FREE (&c); return -1; } mx->mbox = safe_strdup (url.path); if (url.scheme == U_IMAPS) mx->account.flags |= M_ACCT_SSL; FREE (&c); } /* old PINE-compatibility code */ else { FREE (&c); if (sscanf (path, "{%127[^}]}", tmp) != 1) return -1; c = strchr (path, '}'); if (!c) return -1; else /* walk past closing '}' */ mx->mbox = safe_strdup (c+1); if ((c = strrchr (tmp, '@'))) { *c = '\0'; strfcpy (mx->account.user, tmp, sizeof (mx->account.user)); strfcpy (tmp, c+1, sizeof (tmp)); mx->account.flags |= M_ACCT_USER; } if ((n = sscanf (tmp, "%127[^:/]%127s", mx->account.host, tmp)) < 1) { dprint (1, (debugfile, "imap_parse_path: NULL host in %s\n", path)); FREE (&mx->mbox); return -1; } if (n > 1) { if (sscanf (tmp, ":%hu%127s", &(mx->account.port), tmp) >= 1) mx->account.flags |= M_ACCT_PORT; if (sscanf (tmp, "/%s", tmp) == 1) { if (!ascii_strncmp (tmp, "ssl", 3)) mx->account.flags |= M_ACCT_SSL; else { dprint (1, (debugfile, "imap_parse_path: Unknown connection type in %s\n", path)); FREE (&mx->mbox); return -1; } } } } if ((mx->account.flags & M_ACCT_SSL) && !(mx->account.flags & M_ACCT_PORT)) mx->account.port = ImapsPort; return 0; }
RIFActVarBind RIFActVarBind::parse(DPtr<uint8_t> *utf8str) throw(BadAllocException, SizeUnknownException, InvalidCodepointException, InvalidEncodingException, MalformedIRIRefException, TraceableException) { if (utf8str == NULL) { THROW(TraceableException, "utf8str must not be NULL."); } if (!utf8str->sizeKnown()) { THROWX(SizeUnknownException); } const uint8_t *begin = utf8str->dptr(); const uint8_t *end = begin + utf8str->size(); const uint8_t *left_bound = begin; const uint8_t *right_bound = end; for (; left_bound != end && is_space(*left_bound); ++left_bound) { // find first non-space character } if (left_bound == end || *left_bound != to_ascii('(')) { THROW(TraceableException, "Could not find opening parenthesis."); } for (--right_bound; right_bound != left_bound && is_space(*right_bound); --right_bound) { // find last non-space character } if (right_bound == left_bound || *right_bound != to_ascii(')')) { THROW(TraceableException, "Ends without closing parenthesis."); } for (++left_bound; left_bound != right_bound && is_space(*left_bound); ++left_bound) { // find beginning of action variable } if (left_bound == right_bound || *left_bound != to_ascii('?')) { THROW(TraceableException, "Unable to find action variable."); } for (--right_bound; right_bound != left_bound && is_space(*right_bound); --right_bound) { // find end of binding value } if (right_bound == left_bound) { THROW(TraceableException, "Unable to find binding value."); } ++right_bound; const uint8_t *var = left_bound; while (var != right_bound) { for (++var; var != right_bound && !is_space(*var); ++var) { // find end of variable... maybe } DPtr<uint8_t> *varstr = utf8str->sub(left_bound - begin, var - left_bound); RIFVar v; try { v = RIFVar::parse(varstr); varstr->drop(); } catch (BadAllocException &e) { varstr->drop(); RETHROW(e, "Unable to parse action variable."); } catch (InvalidCodepointException &e) { varstr->drop(); RETHROW(e, "Unable to parse action variable."); } catch (InvalidEncodingException &e) { varstr->drop(); RETHROW(e, "Unable to parse action variable."); } catch (TraceableException &e) { varstr->drop(); continue; } const uint8_t *bindval = var; for (; bindval != right_bound && is_space(*bindval); ++bindval) { // find beginning of binding value } if (bindval == right_bound) { THROW(TraceableException, "Unable to find binding value."); } if (right_bound - bindval == 5 && ascii_strncmp(bindval, "New()", 5) == 0) { return RIFActVarBind(v); } DPtr<uint8_t> *framestr = utf8str->sub(bindval - begin, right_bound - bindval); try { RIFAtomic frame = RIFAtomic::parse(framestr); framestr->drop(); framestr = NULL; return RIFActVarBind(v, frame); } catch (BadAllocException &e) { if (framestr != NULL) { framestr->drop(); } RETHROW(e, "Unable to parse binding value."); } catch (InvalidCodepointException &e) { framestr->drop(); RETHROW(e, "Unable to parse binding value."); } catch (InvalidEncodingException &e) { framestr->drop(); RETHROW(e, "Unable to parse binding value."); } catch (MalformedIRIRefException &e) { framestr->drop(); RETHROW(e, "Unable to parse binding value."); } catch (TraceableException &e) { if (framestr != NULL) { framestr->drop(); } RETHROW(e, "Unable to parse binding value."); } } THROW(TraceableException, "Unable to parse action variable binding."); }
RIFActionBlock RIFActionBlock::parse(DPtr<uint8_t> *utf8str) throw(BadAllocException, SizeUnknownException, InvalidCodepointException, InvalidEncodingException, MalformedIRIRefException, TraceableException) { if (utf8str == NULL) { THROW(TraceableException, "utf8str must not be NULL."); } if (!utf8str->sizeKnown()) { THROWX(SizeUnknownException); } const uint8_t *begin = utf8str->dptr(); const uint8_t *end = begin + utf8str->size(); const uint8_t *mark = begin; for (; mark != end && is_space(*mark); ++mark) { // find beginning of action block } if (end - mark < 4) { THROW(TraceableException, "Could not find action block."); } if (ascii_strncmp(mark, "Do", 2) != 0) { THROW(TraceableException, "Action block must start with \"Do\"."); } mark += 2; for (; mark != end && is_space(*mark); ++mark) { // search for left parenthesis } if (mark == end || *mark != to_ascii('(')) { THROW(TraceableException, "Could not find opening parenthesis."); } for (--end; end != mark && is_space(*end); --end) { // find right parenthesis } if (end == mark || *end != to_ascii(')')) { THROW(TraceableException, "Could not find closing parenthesis."); } for (--end; end != mark && is_space(*end); --end) { // find end of last action } ++end; for (++mark; mark != end && is_space(*mark); ++mark) { // find first binding or action } if (mark == end) { THROW(TraceableException, "Action block is (illegaly) empty."); } deque<RIFAction> actions; ActVarMap bindings(RIFVar::cmplt0); bool find_bindings = (*mark == to_ascii('(')); const uint8_t *bound = mark; while (bound != end) { for (; bound != end && *bound != to_ascii(')'); ++bound) { // find end of action block binding or action... maybe } if (bound != end) { ++bound; } DPtr<uint8_t> *str = utf8str->sub(mark - begin, bound - mark); if (find_bindings) { try { RIFActVarBind bind = RIFActVarBind::parse(str); str->drop(); str = NULL; pair<ActVarMap::iterator, bool> p = bindings.insert( pair<RIFVar, RIFActVarBind>(bind.getActVar(), bind)); if (!p.second) { THROW(TraceableException, "Cannot have multiple bindings for same action variable."); } } catch (BadAllocException &e) { str->drop(); RETHROW(e, "Cannot parse action variable binding."); } catch (InvalidCodepointException &e) { str->drop(); RETHROW(e, "Cannot parse action variable binding."); } catch (InvalidEncodingException &e) { str->drop(); RETHROW(e, "Cannot parse action variable binding."); } catch (MalformedIRIRefException &e) { str->drop(); continue; } catch (TraceableException &e) { if (str == NULL) { RETHROW(e, "Malformed action block."); } str->drop(); continue; } } else { try { RIFAction act = RIFAction::parse(str); str->drop(); actions.push_back(act); } catch (BadAllocException &e) { str->drop(); RETHROW(e, "Cannot parse action."); } catch (InvalidCodepointException &e) { str->drop(); RETHROW(e, "Cannot parse action."); } catch (InvalidEncodingException &e) { str->drop(); RETHROW(e, "Cannot parse action."); } catch (MalformedIRIRefException &e) { str->drop(); continue; } catch (TraceableException &e) { str->drop(); continue; } } for (mark = bound; mark != end && is_space(*mark); ++mark) { // find beginning of next action block binding or action... maybe } bound = mark; find_bindings = find_bindings && (*mark == to_ascii('(')); } DPtr<RIFAction> *pact; try { NEW(pact, APtr<RIFAction>, actions.size()); } RETHROW_BAD_ALLOC copy(actions.begin(), actions.end(), pact->dptr()); try { RIFActionBlock block(pact, bindings); pact->drop(); return block; } catch (TraceableException &e) { pact->drop(); RETHROW(e, "Cannot parse action block."); } }
/* imap_browse: IMAP hook into the folder browser, fills out browser_state, * given a current folder to browse */ int imap_browse (char* path, struct browser_state* state) { IMAP_DATA* idata; char buf[LONG_STRING]; char buf2[LONG_STRING]; char nsbuf[LONG_STRING]; char mbox[LONG_STRING]; char list_cmd[5]; IMAP_NAMESPACE_INFO nsi[16]; int home_namespace = 0; int n; int i; int nsup; char ctmp; int nns; char *cur_folder; short showparents = 0; int noselect; int noinferiors; IMAP_MBOX mx; if (imap_parse_path (path, &mx)) { mutt_error (_("%s is an invalid IMAP path"), path); return -1; } strfcpy (list_cmd, option (OPTIMAPLSUB) ? "LSUB" : "LIST", sizeof (list_cmd)); if (!(idata = imap_conn_find (&(mx.account), 0))) goto fail; if (!mx.mbox) { home_namespace = 1; mbox[0] = '\0'; /* Do not replace "" with "INBOX" here */ mx.mbox = safe_strdup(ImapHomeNamespace); nns = 0; if (mutt_bit_isset(idata->capabilities,NAMESPACE)) { mutt_message _("Getting namespaces..."); if (browse_get_namespace (idata, nsbuf, sizeof (nsbuf), nsi, sizeof (nsi), &nns) != 0) goto fail; if (browse_verify_namespace (idata, nsi, nns) != 0) goto fail; } } mutt_message _("Getting folder list..."); /* skip check for parents when at the root */ if (mx.mbox && mx.mbox[0] != '\0') { imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox)); imap_munge_mbox_name (buf, sizeof (buf), mbox); imap_unquote_string(buf); /* As kludgy as it gets */ mbox[sizeof (mbox) - 1] = '\0'; strncpy (mbox, buf, sizeof (mbox) - 1); n = mutt_strlen (mbox); dprint (3, (debugfile, "imap_browse: mbox: %s\n", mbox)); /* if our target exists and has inferiors, enter it if we * aren't already going to */ if (mbox[n-1] != idata->delim) { snprintf (buf, sizeof (buf), "%s \"\" \"%s\"", list_cmd, mbox); imap_cmd_start (idata, buf); do { if (imap_parse_list_response (idata, &cur_folder, &noselect, &noinferiors, &idata->delim) != 0) goto fail; if (cur_folder) { imap_unmunge_mbox_name (cur_folder); if (!noinferiors && cur_folder[0] && (n = strlen (mbox)) < LONG_STRING-1) { mbox[n++] = idata->delim; mbox[n] = '\0'; } } } while (ascii_strncmp (idata->cmd.buf, idata->cmd.seq, SEQLEN)); } /* if we're descending a folder, mark it as current in browser_state */ if (mbox[n-1] == idata->delim) { /* don't show parents in the home namespace */ if (!home_namespace) showparents = 1; imap_qualify_path (buf, sizeof (buf), &mx, mbox); state->folder = safe_strdup (buf); n--; } /* Find superiors to list * Note: UW-IMAP servers return folder + delimiter when asked to list * folder + delimiter. Cyrus servers don't. So we ask for folder, * and tack on delimiter ourselves. * Further note: UW-IMAP servers return nothing when asked for * NAMESPACES without delimiters at the end. Argh! */ for (n--; n >= 0 && mbox[n] != idata->delim ; n--); if (n > 0) /* "aaaa/bbbb/" -> "aaaa" */ { /* forget the check, it is too delicate (see above). Have we ever * had the parent not exist? */ ctmp = mbox[n]; mbox[n] = '\0'; if (showparents) { dprint (3, (debugfile, "imap_init_browse: adding parent %s\n", mbox)); imap_add_folder (idata->delim, mbox, 1, 0, state, 1); } /* if our target isn't a folder, we are in our superior */ if (!state->folder) { /* store folder with delimiter */ mbox[n++] = ctmp; ctmp = mbox[n]; mbox[n] = '\0'; imap_qualify_path (buf, sizeof (buf), &mx, mbox); state->folder = safe_strdup (buf); } mbox[n] = ctmp; } /* "/bbbb/" -> add "/", "aaaa/" -> add "" */ else { char relpath[2]; /* folder may be "/" */ snprintf (relpath, sizeof (relpath), "%c" , n < 0 ? '\0' : idata->delim); if (showparents) imap_add_folder (idata->delim, relpath, 1, 0, state, 1); if (!state->folder) { imap_qualify_path (buf, sizeof (buf), &mx, relpath); state->folder = safe_strdup (buf); } } } /* no namespace, no folder: set folder to host only */ if (!state->folder) { imap_qualify_path (buf, sizeof (buf), &mx, NULL); state->folder = safe_strdup (buf); } if (home_namespace && mbox[0] != '\0') { /* Listing the home namespace, so INBOX should be included. Home * namespace is not "", so we have to list it explicitly. We ask the * server to see if it has descendants. */ dprint (2, (debugfile, "imap_init_browse: adding INBOX\n")); if (browse_add_list_result (idata, "LIST \"\" \"INBOX\"", state, 0)) goto fail; if (!state->entrylen) { mutt_error _("No such folder"); goto fail; } } nsup = state->entrylen; dprint (3, (debugfile, "imap_browse: Quoting mailbox scan: %s -> ", mbox)); snprintf (buf, sizeof (buf), "%s%%", mbox); imap_quote_string (buf2, sizeof (buf2), buf); dprint (3, (debugfile, "%s\n", buf2)); snprintf (buf, sizeof (buf), "%s \"\" %s", list_cmd, buf2); if (browse_add_list_result (idata, buf, state, 0)) goto fail; mutt_clear_error (); qsort(&(state->entry[nsup]),state->entrylen-nsup,sizeof(state->entry[0]), (int (*)(const void*,const void*)) compare_names); if (home_namespace) { /* List additional namespaces */ for (i = 0; i < nns; i++) if (nsi[i].listable && !nsi[i].home_namespace) { imap_add_folder(nsi[i].delim, nsi[i].prefix, nsi[i].noselect, nsi[i].noinferiors, state, 0); dprint (3, (debugfile, "imap_init_browse: adding namespace: %s\n", nsi[i].prefix)); } } FREE (&mx.mbox); return 0; fail: FREE (&mx.mbox); return -1; }
static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen, IMAP_NAMESPACE_INFO* nsi, int nsilen, int* nns) { char *s; int n; char ns[LONG_STRING]; char delim = '/'; int type; int nsbused = 0; int rc; *nns = 0; nsbuf[nsblen-1] = '\0'; imap_cmd_start (idata, "NAMESPACE"); do { if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; s = imap_next_word (idata->cmd.buf); if (ascii_strncasecmp ("NAMESPACE", s, 9) == 0) { /* There are three sections to the response, User, Other, Shared, * and maybe more by extension */ for (type = IMAP_NS_PERSONAL; *s; type++) { s = imap_next_word (s); if (*s && ascii_strncmp (s, "NIL", 3)) { s++; while (*s && *s != ')') { s++; /* skip ( */ /* copy namespace */ n = 0; delim = '\0'; if (*s == '\"') { s++; while (*s && *s != '\"') { if (*s == '\\') s++; ns[n++] = *s; s++; } /* skip trailing ", if we found one, otherwise * imap_next_word will get confused */ if (*s) s++; } else while (*s && !ISSPACE (*s)) { ns[n++] = *s; s++; } ns[n] = '\0'; /* delim? */ s = imap_next_word (s); /* delimiter is meaningless if namespace is "". Why does * Cyrus provide one?! */ if (n && *s && *s == '\"') { if (s[1] && s[2] == '\"') delim = s[1]; else if (s[1] && s[1] == '\\' && s[2] && s[3] == '\"') delim = s[2]; } /* skip "" namespaces, they are already listed at the root */ if ((ns[0] != '\0') && (nsbused < nsblen) && (*nns < nsilen)) { dprint (3, (debugfile, "browse_get_namespace: adding %s\n", ns)); nsi->type = type; /* Cyrus doesn't append the delimiter to the namespace, * but UW-IMAP does. We'll strip it here and add it back * as if it were a normal directory, from the browser */ if (n && (ns[n-1] == delim)) ns[--n] = '\0'; strncpy (nsbuf+nsbused,ns,nsblen-nsbused-1); nsi->prefix = nsbuf+nsbused; nsbused += n+1; nsi->delim = delim; nsi++; (*nns)++; } while (*s && *s != ')') s++; if (*s) s++; } } } } } while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_OK) return -1; return 0; }
RIFAction RIFAction::parse(DPtr<uint8_t> *utf8str) throw(BadAllocException, SizeUnknownException, InvalidCodepointException, InvalidEncodingException, MalformedIRIRefException, TraceableException) { if (utf8str == NULL) { THROW(TraceableException, "utf8str must not be NULL."); } if (!utf8str->sizeKnown()) { THROWX(SizeUnknownException); } const uint8_t *begin = utf8str->dptr(); const uint8_t *end = begin + utf8str->size(); const uint8_t *beginkw = begin; for (; beginkw != end && is_space(*beginkw); ++beginkw) { // find beginning of keyword } if (beginkw == end) { THROW(TraceableException, "No keyword found when parsing RIFAction."); } const uint8_t *endkw = beginkw; for (; endkw != end && is_alnum(*endkw); ++endkw) { // find end of keyword } enum RIFActType type; if (endkw - beginkw == 6) { if (ascii_strncmp(beginkw, "Assert", 6) == 0) { type = ASSERT_FACT; } else if (ascii_strncmp(beginkw, "Modify", 6) == 0) { type = MODIFY; } else { THROW(TraceableException, "Unrecognized RIFAction type."); } } else if (endkw - beginkw == 7) { if (ascii_strncmp(beginkw, "Retract", 7) == 0) { type = RETRACT_FACT; // validate later } else if (ascii_strncmp(beginkw, "Execute", 7) == 0) { type = EXECUTE; } else { THROW(TraceableException, "Unrecognized RIFAction type."); } } else { THROW(TraceableException, "Unrecognized RIFAction type."); } const uint8_t *left_bound = endkw; for (; left_bound != end && *left_bound != to_ascii('('); ++left_bound) { // find left paren enclosing target } if (left_bound == end) { THROW(TraceableException, "Could not find left paren when parsing RIFAction."); } const uint8_t *right_bound = end; for (--right_bound; right_bound != left_bound && *right_bound != to_ascii(')'); --right_bound) { // find right paren enclosing target } if (right_bound == left_bound) { THROW(TraceableException, "Could not find right paren when parsing RIFAction."); } for (++left_bound; left_bound != right_bound && is_space(*left_bound); ++left_bound) { // find left bound of target } if (left_bound == right_bound) { if (type == EXECUTE) { return RIFAction(); } THROW(TraceableException, "No target specified for RIFAction."); } for (--right_bound; right_bound != left_bound && is_space(*right_bound); --right_bound) { // find right bound of target } ++right_bound; DPtr<uint8_t> *targetstr = utf8str->sub(left_bound - begin, right_bound - left_bound); try { RIFAtomic atom = RIFAtomic::parse(targetstr); RIFAction act (type, atom); targetstr->drop(); return act; } catch (BadAllocException &e) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } catch (InvalidCodepointException &e) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } catch (InvalidEncodingException &e) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } catch (MalformedIRIRefException &e) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } catch (BaseException<enum RIFActType> &e) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } catch (TraceableException &e) { if (type != RETRACT_FACT) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } } try { RIFTerm term = RIFTerm::parse(targetstr); RIFAction act (term); targetstr->drop(); return act; } catch (BadAllocException &e) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } catch (InvalidCodepointException &e) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } catch (InvalidEncodingException &e) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } catch (MalformedIRIRefException &e) { targetstr->drop(); RETHROW(e, "Unable to parse target."); } catch (TraceableException &e) { // ignore and check if RETRACT_SLOTS } RIFTerm obj, attr; begin = targetstr->dptr(); end = begin + targetstr->size(); while (begin != end) { for (; begin != end && is_space(*begin); ++begin) { // creep forward to first non-space } for (++begin; begin != end && !is_space(*begin); ++begin) { // search for space between terms } if (begin == end) { targetstr->drop(); THROW(TraceableException, "Invalid RETRACT target."); } DPtr<uint8_t> *str = targetstr->sub(0, begin - targetstr->dptr()); try { obj = RIFTerm::parse(str); str->drop(); } catch (TraceableException &e) { str->drop(); continue; } for (++begin; begin != end && is_space(*begin); ++begin) { // search for second term } str = targetstr->sub(begin - targetstr->dptr(), end - begin); try { attr = RIFTerm::parse(str); str->drop(); } catch (TraceableException &e) { str->drop(); continue; } try { targetstr->drop(); return RIFAction(obj, attr); } RETHROW_BAD_ALLOC } targetstr->drop(); THROW(TraceableException, "Invalid RETRACT target."); }