Beispiel #1
0
/* imap_pretty_mailbox: called by mutt_pretty_mailbox to make IMAP paths
 *   look nice. */
void imap_pretty_mailbox (char* path)
{
  IMAP_MBOX home, target;
  ciss_url_t url;
  char* delim;
  int tlen;
  int hlen = 0;
  char home_match = 0;

  if (imap_parse_path (path, &target) < 0)
    return;

  tlen = mutt_strlen (target.mbox);
  /* check whether we can do '=' substitution */
  if (mx_is_imap(Maildir) && !imap_parse_path (Maildir, &home))
  {
    hlen = mutt_strlen (home.mbox);
    if (tlen && mutt_account_match (&home.account, &target.account) &&
	!mutt_strncmp (home.mbox, target.mbox, hlen))
    {
      if (! hlen)
	home_match = 1;
      else if (ImapDelimChars)
	for (delim = ImapDelimChars; *delim != '\0'; delim++)
	  if (target.mbox[hlen] == *delim)
	    home_match = 1;
    }
    FREE (&home.mbox);
  }

  /* do the '=' substitution */
  if (home_match) {
    *path++ = '=';
    /* copy remaining path, skipping delimiter */
    if (! hlen)
      hlen = -1;
    memcpy (path, target.mbox + hlen + 1, tlen - hlen - 1);
    path[tlen - hlen - 1] = '\0';
  }
  else
  {
    mutt_account_tourl (&target.account, &url);
    url.path = target.mbox;
    /* FIXME: That hard-coded constant is bogus. But we need the actual
     *   size of the buffer from mutt_pretty_mailbox. And these pretty
     *   operations usually shrink the result. Still... */
    url_ciss_tostring (&url, path, 1024, 0);
  }

  FREE (&target.mbox);
}
Beispiel #2
0
/*
BALSA: this function is needed because the lower-level imap_delete_mailbox
segfaults when called from Balsa.  It doesn't especially belong here,
but it roughly complements imap_mailbox_create above.
*/
int imap_mailbox_delete(const char* folder)
{
  IMAP_DATA* idata;
  IMAP_MBOX mx;

  if (imap_parse_path (folder, &mx) < 0)
  {
    dprint (1, (debugfile, "imap_mailbox_delete: Bad path %s\n",
      folder));
    return -1;
  }

  if (!(idata = imap_conn_find (&mx.account, M_IMAP_CONN_NONEW)))
  {
    dprint (1, (debugfile,
               "imap_mailbox_delete: Couldn't find open connection to %s",
               mx.account.host));
    goto fail;
  }

  /* imap_delete_mailbox takes the CONTEXT as an argument,
   * but expects the data field to point to IMAP_DATA:
   */
  if (!idata->ctx->data)
    idata->ctx->data = idata;
  if (!*mx.mbox || imap_delete_mailbox (idata->ctx, mx) < 0)
    goto fail;

  FREE (&mx.mbox);
  return 0;

 fail:
  FREE (&mx.mbox);
  return -1;
}
Beispiel #3
0
int imap_mailbox_rename (const char* url, const char* parent, 
                         const char* subfolder, int subscribe)
{
  IMAP_DATA* idata;
  IMAP_MBOX mx;
  char buf[LONG_STRING];
  short n;
  BUFFER new_url;

  memset (&new_url, 0, sizeof (new_url));
  if (imap_parse_path (url, &mx) < 0)
  {
    dprint (1, (debugfile, "imap_mailbox_rename: Bad path %s\n", url));
    return -1;
  }

  if (!(idata = imap_conn_find (&mx.account, M_IMAP_CONN_NONEW)))
  {
    dprint (1, (debugfile, "imap_mailbox_rename: Couldn't find open connection to %s", mx.account.host));
    goto fail;
  }
  
  strfcpy (buf, parent, sizeof (buf));

  /* append a delimiter if necessary */
  n = mutt_strlen (buf);
  if (n && (n < sizeof (buf) - 1) && (buf[n-1] != idata->delim))
  {
    buf[n++] = idata->delim;
    buf[n] = '\0';
  }
  
  strfcpy (buf + n, subfolder, sizeof (buf) - n);

  imap_subscribe(url, 0);
  if (imap_rename_mailbox (idata, mx.mbox, buf) < 0)
    goto fail;

  if (subscribe) {
    char* slash = strchr(url+8, '/');
    if(slash) {
      mutt_buffer_add(&new_url, url, slash-url+1);
      mutt_buffer_addstr(&new_url, parent);
      mutt_buffer_addch (&new_url, idata->delim);
      mutt_buffer_addstr(&new_url, subfolder);
      if (imap_subscribe(new_url.data, 1) < 0)
        goto fail;
    }
  }

  FREE (&new_url.data);
  FREE (&mx.mbox);
  return 0;

 fail:
  FREE (&new_url.data);
  FREE (&mx.mbox);
  return -1;
}
Beispiel #4
0
/* imap_expand_path: IMAP implementation of mutt_expand_path. Rewrite
 *   an IMAP path in canonical and absolute form.
 * Inputs: a buffer containing an IMAP path, and the number of bytes in
 *   that buffer.
 * Outputs: The buffer is rewritten in place with the canonical IMAP path.
 * Returns 0 on success, or -1 if imap_parse_path chokes or url_ciss_tostring
 *   fails, which it might if there isn't enough room in the buffer. */
int imap_expand_path (char *path, size_t len)
{
  IMAP_MBOX mx;
  ciss_url_t url;
  int rc;

  if (imap_parse_path (path, &mx) < 0)
    return -1;

  mutt_account_tourl (&mx.account, &url);
  url.path = mx.mbox;

  rc = url_ciss_tostring (&url, path, len, U_DECODE_PASSWD);
  mem_free (&mx.mbox);

  return rc;
}
Beispiel #5
0
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;
}
Beispiel #6
0
/* imap_expand_path: IMAP implementation of mutt_expand_path. Rewrite
 *   an IMAP path in canonical and absolute form.
 * Inputs: a buffer containing an IMAP path, and the number of bytes in
 *   that buffer.
 * Outputs: The buffer is rewritten in place with the canonical IMAP path.
 * Returns 0 on success, or -1 if imap_parse_path chokes or url_ciss_tostring
 *   fails, which it might if there isn't enough room in the buffer. */
int imap_expand_path (char* path, size_t len)
{
  IMAP_MBOX mx;
  IMAP_DATA* idata;
  ciss_url_t url;
  char fixedpath[LONG_STRING];
  int rc;

  if (imap_parse_path (path, &mx) < 0)
    return -1;

  idata = imap_conn_find (&mx.account, M_IMAP_CONN_NONEW);
  mutt_account_tourl (&mx.account, &url);
  imap_fix_path (idata, mx.mbox, fixedpath, sizeof (fixedpath));
  url.path = fixedpath;

  rc = url_ciss_tostring (&url, path, len, U_DECODE_PASSWD);
  FREE (&mx.mbox);

  return rc;
}
Beispiel #7
0
header_cache_t* imap_hcache_open (IMAP_DATA* idata, const char* path)
{
  IMAP_MBOX mx;
  ciss_url_t url;
  char cachepath[LONG_STRING];
  char mbox[LONG_STRING];

  if (path)
    imap_cachepath (idata, path, mbox, sizeof (mbox));
  else
  {
    if (!idata->ctx || imap_parse_path (idata->ctx->path, &mx) < 0)
      return NULL;

    imap_cachepath (idata, mx.mbox, mbox, sizeof (mbox));
    FREE (&mx.mbox);
  }

  mutt_account_tourl (&idata->conn->account, &url);
  url.path = mbox;
  url_ciss_tostring (&url, cachepath, sizeof (cachepath), U_PATH);

  return mutt_hcache_open (HeaderCache, cachepath, imap_hcache_namer);
}
Beispiel #8
0
int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
{
  IMAP_DATA* idata;
  FILE *fp;
  char buf[LONG_STRING];
  char mbox[LONG_STRING];
  char mailbox[LONG_STRING];
  char internaldate[IMAP_DATELEN];
  char imap_flags[SHORT_STRING];
  size_t len;
  progress_t progressbar;
  size_t sent;
  int c, last;
  IMAP_MBOX mx;
  int rc;

  idata = (IMAP_DATA*) ctx->data;

  if (imap_parse_path (ctx->path, &mx))
    return -1;

  imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
  if (!*mailbox)
    strfcpy (mailbox, "INBOX", sizeof (mailbox));

  if ((fp = fopen (msg->path, "r")) == NULL)
  {
    mutt_perror (msg->path);
    goto fail;
  }

  /* currently we set the \Seen flag on all messages, but probably we
   * should scan the message Status header for flag info. Since we're
   * already rereading the whole file for length it isn't any more
   * expensive (it'd be nice if we had the file size passed in already
   * by the code that writes the file, but that's a lot of changes.
   * Ideally we'd have a HEADER structure with flag info here... */
  for (last = EOF, len = 0; (c = fgetc(fp)) != EOF; last = c)
  {
    if(c == '\n' && last != '\r')
      len++;

    len++;
  }
  rewind (fp);

  mutt_progress_init (&progressbar, _("Uploading message..."),
		      MUTT_PROGRESS_SIZE, NetInc, len);

  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mailbox);
  imap_make_date (internaldate, msg->received);

  imap_flags[0] = imap_flags[1] = 0;
  if (msg->flags.read)
    safe_strcat (imap_flags, sizeof (imap_flags), " \\Seen");
  if (msg->flags.replied)
    safe_strcat (imap_flags, sizeof (imap_flags), " \\Answered");
  if (msg->flags.flagged)
    safe_strcat (imap_flags, sizeof (imap_flags), " \\Flagged");
  if (msg->flags.draft)
    safe_strcat (imap_flags, sizeof (imap_flags), " \\Draft");

  snprintf (buf, sizeof (buf), "APPEND %s (%s) \"%s\" {%lu}", mbox,
            imap_flags + 1,
	    internaldate,
	    (unsigned long) len);

  imap_cmd_start (idata, buf);

  do
    rc = imap_cmd_step (idata);
  while (rc == IMAP_CMD_CONTINUE);

  if (rc != IMAP_CMD_RESPOND)
  {
    char *pc;

    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n",
		idata->buf));

    pc = idata->buf + SEQLEN;
    SKIPWS (pc);
    pc = imap_next_word (pc);
    mutt_error ("%s", pc);
    mutt_sleep (1);
    safe_fclose (&fp);
    goto fail;
  }

  for (last = EOF, sent = len = 0; (c = fgetc(fp)) != EOF; last = c)
  {
    if (c == '\n' && last != '\r')
      buf[len++] = '\r';

    buf[len++] = c;

    if (len > sizeof(buf) - 3)
    {
      sent += len;
      flush_buffer(buf, &len, idata->conn);
      mutt_progress_update (&progressbar, sent, -1);
    }
  }

  if (len)
    flush_buffer(buf, &len, idata->conn);

  mutt_socket_write (idata->conn, "\r\n");
  safe_fclose (&fp);

  do
    rc = imap_cmd_step (idata);
  while (rc == IMAP_CMD_CONTINUE);

  if (!imap_code (idata->buf))
  {
    char *pc;

    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n",
		idata->buf));
    pc = idata->buf + SEQLEN;
    SKIPWS (pc);
    pc = imap_next_word (pc);
    mutt_error ("%s", pc);
    mutt_sleep (1);
    goto fail;
  }

  FREE (&mx.mbox);
  return 0;

 fail:
  FREE (&mx.mbox);
  return -1;
}
Beispiel #9
0
/* 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;
}
Beispiel #10
0
/* imap_add_folder: add a folder name to the browser list, formatting it as
 *   necessary. */
static void imap_add_folder (char delim, char *folder, int noselect,
  int noinferiors, struct browser_state *state, short isparent)
{
  char tmp[LONG_STRING];
  char relpath[LONG_STRING];
  IMAP_MBOX mx;

  if (imap_parse_path (state->folder, &mx))
    return;

  imap_unmunge_mbox_name (folder);

  if (state->entrylen + 1 == state->entrymax)
  {
    safe_realloc ((void **) &state->entry,
      sizeof (struct folder_file) * (state->entrymax += 256));
    memset (state->entry + state->entrylen, 0,
      (sizeof (struct folder_file) * (state->entrymax - state->entrylen)));
  }

  /* render superiors as unix-standard ".." */
  if (isparent)
    strfcpy (relpath, "../", sizeof (relpath));
  /* strip current folder from target, to render a relative path */
  else if (!mutt_strncmp (mx.mbox, folder, mutt_strlen (mx.mbox)))
    strfcpy (relpath, folder + mutt_strlen (mx.mbox), sizeof (relpath));
  else
    strfcpy (relpath, folder, sizeof (relpath));

  /* apply filemask filter. This should really be done at menu setup rather
   * than at scan, since it's so expensive to scan. But that's big changes
   * to browser.c */
  if (!((regexec (Mask.rx, relpath, 0, NULL, 0) == 0) ^ Mask.not))
  {
    FREE (&mx.mbox);
    return;
  }

  imap_qualify_path (tmp, sizeof (tmp), &mx, folder);
  (state->entry)[state->entrylen].name = safe_strdup (tmp);

  /* mark desc with delim in browser if it can have subfolders */
  if (!isparent && !noinferiors && strlen (relpath) < sizeof (relpath) - 1)
  {
    relpath[strlen (relpath) + 1] = '\0';
    relpath[strlen (relpath)] = delim;
  }
  
  (state->entry)[state->entrylen].desc = safe_strdup (relpath);

  (state->entry)[state->entrylen].imap = 1;
  /* delimiter at the root is useless. */
  if (folder[0] == '\0')
    delim = '\0';
  (state->entry)[state->entrylen].delim = delim;
  (state->entry)[state->entrylen].selectable = !noselect;
  (state->entry)[state->entrylen].inferiors = !noinferiors;
  (state->entrylen)++;

  FREE (&mx.mbox);
}
Beispiel #11
0
int imap_mailbox_create (const char* folder, const char* subfolder,
                         int subscribe)
#endif
{
  IMAP_DATA* idata;
  IMAP_MBOX mx;
  char buf[LONG_STRING];
  short n;

  if (imap_parse_path (folder, &mx) < 0)
  {
    dprint (1, (debugfile, "imap_mailbox_create: Bad starting path %s\n",
      folder));
    return -1;
  }

  if (!(idata = imap_conn_find (&mx.account, M_IMAP_CONN_NONEW)))
  {
    dprint (1, (debugfile, "imap_mailbox_create: Couldn't find open connection to %s", mx.account.host));
    goto fail;
  }
  
  strfcpy (buf, NONULL (mx.mbox), sizeof (buf));

  /* append a delimiter if necessary */
  n = mutt_strlen (buf);
  if (n && (n < sizeof (buf) - 1) && (buf[n-1] != idata->delim))
  {
    buf[n++] = idata->delim;
    buf[n] = '\0';
  }
  
#ifndef LIBMUTT
  if (mutt_get_field (_("Create mailbox: "), buf, sizeof (buf), M_FILE) < 0)
    goto fail;

  if (!mutt_strlen (buf))
    {
      mutt_error (_("Mailbox must have a name."));
      mutt_sleep(1);
    goto fail;
    }
#else
  strfcpy (buf + n, subfolder, sizeof (buf) - n);
#endif


  if (imap_create_mailbox (idata, buf) < 0)
    goto fail;

#ifndef LIBMUTT
  mutt_message _("Mailbox created.");
  mutt_sleep (0);
#else
  if (subscribe) {
    snprintf(buf, sizeof (buf), "%s%c%s", folder, idata->delim, subfolder);
    if (imap_subscribe(buf, 1) < 0)
      goto fail;
  }
#endif

  FREE (&mx.mbox);
  return 0;

 fail:
  FREE (&mx.mbox);
  return -1;
}