New file containing camel_imap_command and friends. Major
* providers/imap/camel-imap-command.c: New file containing
camel_imap_command and friends. Major camel_imap_command rewrite
to remove duplicated code, make the parsing of literals be
more safe/correct, deal with RECENT/EXPUNGE responses more
consistently, and make it possible to implement the AUTHENTICATE
command.
* providers/imap/camel-imap-utils.c (imap_parse_nstring): New
function, to parse an IMAP "nstring".
* providers/imap/camel-imap-store.c: Move command stuff to
camel-imap-command.c. Update for camel_imap_command changes.
* providers/imap/camel-imap-folder.c: Update for
camel_imap_command changes.
(imap_append_message): CRLF filter the message before sending it.
* providers/imap/Makefile.am: Add camel-imap-command.[ch], remove
camel-imap-stream.[ch] for now.
svn path=/trunk/; revision=5693
This commit is contained in:
@ -1,3 +1,25 @@
|
||||
2000-10-03 Dan Winship <danw@helixcode.com>
|
||||
|
||||
* providers/imap/camel-imap-command.c: New file containing
|
||||
camel_imap_command and friends. Major camel_imap_command rewrite
|
||||
to remove duplicated code, make the parsing of literals be
|
||||
more safe/correct, deal with RECENT/EXPUNGE responses more
|
||||
consistently, and make it possible to implement the AUTHENTICATE
|
||||
command.
|
||||
|
||||
* providers/imap/camel-imap-utils.c (imap_parse_nstring): New
|
||||
function, to parse an IMAP "nstring".
|
||||
|
||||
* providers/imap/camel-imap-store.c: Move command stuff to
|
||||
camel-imap-command.c. Update for camel_imap_command changes.
|
||||
|
||||
* providers/imap/camel-imap-folder.c: Update for
|
||||
camel_imap_command changes.
|
||||
(imap_append_message): CRLF filter the message before sending it.
|
||||
|
||||
* providers/imap/Makefile.am: Add camel-imap-command.[ch], remove
|
||||
camel-imap-stream.[ch] for now.
|
||||
|
||||
2000-10-02 Jeffrey Stedfast <fejj@helixcode.com>
|
||||
|
||||
* camel-mime-message.c (camel_mime_message_has_8bit_parts): New
|
||||
|
||||
@ -20,16 +20,16 @@ INCLUDES = -I.. \
|
||||
-DG_LOG_DOMAIN=\"camel-imap-provider\"
|
||||
|
||||
libcamelimap_la_SOURCES = \
|
||||
camel-imap-command.c \
|
||||
camel-imap-folder.c \
|
||||
camel-imap-provider.c \
|
||||
camel-imap-store.c \
|
||||
camel-imap-stream.c \
|
||||
camel-imap-utils.c
|
||||
|
||||
libcamelimapinclude_HEADERS = \
|
||||
camel-imap-command.h \
|
||||
camel-imap-folder.h \
|
||||
camel-imap-store.h \
|
||||
camel-imap-stream.h \
|
||||
camel-imap-utils.h
|
||||
|
||||
libcamelimap_la_LDFLAGS = -version-info 0:0:0
|
||||
|
||||
391
camel/providers/imap/camel-imap-command.c
Normal file
391
camel/providers/imap/camel-imap-command.c
Normal file
@ -0,0 +1,391 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/* camel-imap-command.c: IMAP command sending/parsing routines */
|
||||
|
||||
/*
|
||||
* Authors:
|
||||
* Dan Winship <danw@helixcode.com>
|
||||
* Jeffrey Stedfast <fejj@helixcode.com>
|
||||
*
|
||||
* Copyright 2000 Helix Code, Inc. (www.helixcode.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "camel-imap-command.h"
|
||||
#include "camel-imap-utils.h"
|
||||
#include "camel-imap-folder.h"
|
||||
#include <camel/camel-exception.h>
|
||||
|
||||
static char *imap_read_untagged (CamelImapStore *store, char *line,
|
||||
CamelException *ex);
|
||||
static CamelImapResponse *imap_read_response (CamelImapStore *store,
|
||||
CamelException *ex);
|
||||
|
||||
/**
|
||||
* camel_imap_command: Send a command to a IMAP server and get a response
|
||||
* @store: the IMAP store
|
||||
* @folder: The folder to perform the operation in (or %NULL if not
|
||||
* relevant).
|
||||
* @ex: a CamelException
|
||||
* @fmt: a printf-style format string, followed by arguments
|
||||
*
|
||||
* This camel method sends the IMAP command specified by @fmt and the
|
||||
* following arguments to the IMAP store specified by @store. It then
|
||||
* reads the server's response(s) and parses the final result.
|
||||
*
|
||||
* Return value: %NULL if an error occurred (in which case @ex will
|
||||
* be set). Otherwise, a CamelImapResponse describing the server's
|
||||
* response, which the caller must free with camel_imap_response_free().
|
||||
**/
|
||||
CamelImapResponse *
|
||||
camel_imap_command (CamelImapStore *store, CamelFolder *folder,
|
||||
CamelException *ex, const char *fmt, ...)
|
||||
{
|
||||
gchar *cmdbuf;
|
||||
va_list ap;
|
||||
|
||||
/* Check for current folder */
|
||||
if (folder && folder != store->current_folder) {
|
||||
char *folder_path;
|
||||
CamelImapResponse *response;
|
||||
|
||||
folder_path = camel_imap_store_folder_path (store,
|
||||
folder->full_name);
|
||||
response = camel_imap_command (store, NULL, ex,
|
||||
"SELECT %s", folder_path);
|
||||
g_free (folder_path);
|
||||
|
||||
if (!response) {
|
||||
store->current_folder = NULL;
|
||||
return NULL;
|
||||
}
|
||||
camel_imap_response_free (response);
|
||||
|
||||
store->current_folder = folder;
|
||||
}
|
||||
|
||||
/* Send the command */
|
||||
va_start (ap, fmt);
|
||||
cmdbuf = g_strdup_vprintf (fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex,
|
||||
"A%.5d %s\r\n", store->command++,
|
||||
cmdbuf);
|
||||
g_free (cmdbuf);
|
||||
if (camel_exception_is_set (ex))
|
||||
return NULL;
|
||||
|
||||
/* Read the response. */
|
||||
return imap_read_response (store, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* camel_imap_command_continuation: Send more command data to the IMAP server
|
||||
* @store: the IMAP store
|
||||
* @ex: a CamelException
|
||||
* @cmdbuf: buffer containing the response/request data
|
||||
*
|
||||
* This method is for sending continuing responses to the IMAP server
|
||||
* after camel_imap_command returns a CAMEL_IMAP_PLUS response.
|
||||
*
|
||||
* Return value: as for camel_imap_command()
|
||||
**/
|
||||
CamelImapResponse *
|
||||
camel_imap_command_continuation (CamelImapStore *store, CamelException *ex,
|
||||
const char *cmdbuf)
|
||||
{
|
||||
if (camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex,
|
||||
"%s\r\n", cmdbuf) < 0)
|
||||
return NULL;
|
||||
|
||||
return imap_read_response (store, ex);
|
||||
}
|
||||
|
||||
/* Read the response to an IMAP command. */
|
||||
static CamelImapResponse *
|
||||
imap_read_response (CamelImapStore *store, CamelException *ex)
|
||||
{
|
||||
CamelImapResponse *response;
|
||||
int number, recent = 0;
|
||||
GArray *expunged = NULL;
|
||||
char *respbuf, *retcode, *p;
|
||||
|
||||
/* Read first line */
|
||||
if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store),
|
||||
&respbuf, ex) < 0)
|
||||
return NULL;
|
||||
|
||||
response = g_new0 (CamelImapResponse, 1);
|
||||
response->untagged = g_ptr_array_new ();
|
||||
|
||||
/* Check for untagged data */
|
||||
while (!strncmp (respbuf, "* ", 2)) {
|
||||
/* Read the rest of the response if it is multi-line. */
|
||||
respbuf = imap_read_untagged (store, respbuf, ex);
|
||||
if (camel_exception_is_set (ex))
|
||||
break;
|
||||
|
||||
/* If it starts with a number, we might deal with
|
||||
* it ourselves.
|
||||
*/
|
||||
number = strtoul (respbuf + 2, &p, 10);
|
||||
if (p != respbuf + 2) {
|
||||
p = imap_next_word (p);
|
||||
if (!g_strcasecmp (p, "RECENT")) {
|
||||
recent = number;
|
||||
g_free (respbuf);
|
||||
goto next;
|
||||
} else if (!g_strcasecmp (p, "EXPUNGE")) {
|
||||
if (!expunged) {
|
||||
expunged = g_array_new (FALSE, FALSE,
|
||||
sizeof (int));
|
||||
}
|
||||
g_array_append_val (expunged, number);
|
||||
g_free (respbuf);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_add (response->untagged, respbuf);
|
||||
next:
|
||||
if (camel_remote_store_recv_line (
|
||||
CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update the summary */
|
||||
if (store->current_folder && (recent > 0 || expunged)) {
|
||||
camel_imap_folder_changed (store->current_folder, recent,
|
||||
expunged, NULL);
|
||||
}
|
||||
if (expunged)
|
||||
g_array_free (expunged, TRUE);
|
||||
|
||||
if (camel_exception_is_set (ex)) {
|
||||
camel_imap_response_free (response);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
response->status = respbuf;
|
||||
|
||||
/* Check for OK or continuation response. */
|
||||
if (!strncmp (respbuf, "+ ", 2))
|
||||
return response;
|
||||
retcode = imap_next_word (respbuf);
|
||||
if (!strncmp (retcode, "OK", 2))
|
||||
return response;
|
||||
|
||||
/* We should never get BAD, or anything else but +, OK, or NO
|
||||
* for that matter.
|
||||
*/
|
||||
if (strncmp (retcode, "NO", 2) != 0) {
|
||||
g_warning ("Unexpected response from IMAP server: %s",
|
||||
respbuf);
|
||||
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
|
||||
"Unexpected response from IMAP server: "
|
||||
"%s", respbuf);
|
||||
camel_imap_response_free (response);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retcode = imap_next_word (retcode);
|
||||
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
|
||||
"IMAP command failed: %s",
|
||||
retcode ? retcode : "Unknown error");
|
||||
camel_imap_response_free (response);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Given a line that is the start of an untagged response, read and
|
||||
* return the complete response. (This will be a no-op if the line
|
||||
* in question doesn't end with a literal.)
|
||||
*
|
||||
* FIXME: this won't deal with multiple literals in a single response.
|
||||
*/
|
||||
static char *
|
||||
imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex)
|
||||
{
|
||||
int fulllen, length, left, i;
|
||||
GPtrArray *data;
|
||||
char *end, *p;
|
||||
|
||||
p = strrchr (line, '{');
|
||||
if (!p)
|
||||
return line;
|
||||
|
||||
length = strtoul (p + 1, &end, 10);
|
||||
if (*end != '}' || *(end + 1) || end == p + 1)
|
||||
return line;
|
||||
|
||||
fulllen = length + strlen (line) + 1;
|
||||
|
||||
/* OK. We have a literal. @length is the length including CRLF
|
||||
* pairs, which camel_remote_store_recv_line won't return.
|
||||
*/
|
||||
data = g_ptr_array_new ();
|
||||
g_ptr_array_add (data, line);
|
||||
left = length;
|
||||
while (1) {
|
||||
if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store),
|
||||
&line, ex) < 0) {
|
||||
for (i = 0; i < data->len; i++)
|
||||
g_free (data->pdata[i]);
|
||||
g_ptr_array_free (data, TRUE);
|
||||
return NULL;
|
||||
}
|
||||
g_ptr_array_add (data, line);
|
||||
|
||||
if (left <= 0)
|
||||
break;
|
||||
|
||||
left -= strlen (line) + 2;
|
||||
|
||||
/* The output string will have only LF, not CRLF, so
|
||||
* decrement the length by one.
|
||||
*/
|
||||
length--;
|
||||
}
|
||||
|
||||
/* p points to the "{" in the line that starts the literal.
|
||||
* The length of the CR-less response must be less than or
|
||||
* equal to the length of the response with CRs, therefore
|
||||
* overwriting the old value with the new value cannot cause
|
||||
* an overrun.
|
||||
*/
|
||||
sprintf (p, "{%d}", length);
|
||||
|
||||
/* Now reassemble the data. */
|
||||
p = line = g_malloc (fulllen + 1);
|
||||
for (i = 0; i < data->len; i++) {
|
||||
length = strlen (data->pdata[i]);
|
||||
memcpy (p, data->pdata[i], length);
|
||||
g_free (data->pdata[i]);
|
||||
p += length;
|
||||
*p++ = '\n';
|
||||
}
|
||||
*p = '\0';
|
||||
g_ptr_array_free (data, TRUE);
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* camel_imap_response_free:
|
||||
* response: a CamelImapResponse:
|
||||
*
|
||||
* Frees all of the data in @response.
|
||||
**/
|
||||
void
|
||||
camel_imap_response_free (CamelImapResponse *response)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!response)
|
||||
return;
|
||||
for (i = 0; i < response->untagged->len; i++)
|
||||
g_free (response->untagged->pdata[i]);
|
||||
g_ptr_array_free (response->untagged, TRUE);
|
||||
g_free (response->status);
|
||||
g_free (response);
|
||||
}
|
||||
|
||||
/**
|
||||
* camel_imap_response_extract:
|
||||
* @response: the response data returned from camel_imap_command
|
||||
* @type: the response type to extract
|
||||
* @ex: a CamelException
|
||||
*
|
||||
* This checks that @response contains a single untagged response of
|
||||
* type @type and returns just that response data. If @response
|
||||
* doesn't contain the right information, the function will set @ex and
|
||||
* return %NULL. Either way, @response will be freed.
|
||||
*
|
||||
* Return value: the desired response string, which the caller must free.
|
||||
**/
|
||||
char *
|
||||
camel_imap_response_extract (CamelImapResponse *response, const char *type,
|
||||
CamelException *ex)
|
||||
{
|
||||
int len = strlen (type), i;
|
||||
char *resp;
|
||||
|
||||
for (i = 0; i < response->untagged->len; i++) {
|
||||
resp = response->untagged->pdata[i];
|
||||
/* Skip "* ", and initial sequence number, if present */
|
||||
strtoul (resp + 2, &resp, 10);
|
||||
if (*resp == ' ')
|
||||
resp++;
|
||||
|
||||
if (!g_strncasecmp (resp, type, len))
|
||||
break;
|
||||
g_free (resp);
|
||||
}
|
||||
|
||||
if (i < response->untagged->len) {
|
||||
resp = response->untagged->pdata[i];
|
||||
for (i++; i < response->untagged->len; i++)
|
||||
g_free (response->untagged->pdata[i]);
|
||||
} else {
|
||||
resp = NULL;
|
||||
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
|
||||
"IMAP server response did not contain "
|
||||
"%s information", type);
|
||||
}
|
||||
|
||||
g_ptr_array_free (response->untagged, TRUE);
|
||||
g_free (response->status);
|
||||
g_free (response);
|
||||
return resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* camel_imap_response_extract_continuation:
|
||||
* @response: the response data returned from camel_imap_command
|
||||
* @ex: a CamelException
|
||||
*
|
||||
* This checks that @response contains a continuation response, and
|
||||
* returns just that data. If @response doesn't contain a continuation
|
||||
* response, the function will set @ex and return %NULL. Either way,
|
||||
* @response will be freed.
|
||||
*
|
||||
* Return value: the desired response string, which the caller must free.
|
||||
**/
|
||||
char *
|
||||
camel_imap_response_extract_continuation (CamelImapResponse *response,
|
||||
CamelException *ex)
|
||||
{
|
||||
char *status;
|
||||
|
||||
if (response->status && !strncmp (response->status, "+ ", 2)) {
|
||||
status = response->status;
|
||||
response->status = NULL;
|
||||
camel_imap_response_free (response);
|
||||
return status;
|
||||
}
|
||||
|
||||
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
|
||||
"Unexpected OK response from IMAP server: %s",
|
||||
response->status);
|
||||
camel_imap_response_free (response);
|
||||
return NULL;
|
||||
}
|
||||
58
camel/providers/imap/camel-imap-command.h
Normal file
58
camel/providers/imap/camel-imap-command.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/* camel-imap-command.h: IMAP command sending/parsing routines */
|
||||
|
||||
/*
|
||||
* Authors:
|
||||
* Dan Winship <danw@helixcode.com>
|
||||
* Jeffrey Stedfast <fejj@helixcode.com>
|
||||
*
|
||||
* Copyright (C) 2000 Helix Code, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CAMEL_IMAP_COMMAND_H
|
||||
#define CAMEL_IMAP_COMMAND_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#pragma }
|
||||
#endif /* __cplusplus }*/
|
||||
|
||||
#include "camel-imap-store.h"
|
||||
|
||||
typedef struct {
|
||||
GPtrArray *untagged;
|
||||
char *status;
|
||||
} CamelImapResponse;
|
||||
|
||||
CamelImapResponse *camel_imap_command (CamelImapStore *store,
|
||||
CamelFolder *folder,
|
||||
CamelException *ex,
|
||||
const char *fmt, ...);
|
||||
CamelImapResponse *camel_imap_command_continuation (CamelImapStore *store,
|
||||
CamelException *ex,
|
||||
const char *cmdbuf);
|
||||
|
||||
void camel_imap_response_free (CamelImapResponse *response);
|
||||
char *camel_imap_response_extract (CamelImapResponse *response,
|
||||
const char *type,
|
||||
CamelException *ex);
|
||||
char *camel_imap_response_extract_continuation (CamelImapResponse *response,
|
||||
CamelException *ex);
|
||||
|
||||
#endif /* CAMEL_IMAP_COMMAND_H */
|
||||
@ -37,6 +37,7 @@
|
||||
#include <gal/util/e-util.h>
|
||||
|
||||
#include "camel-imap-folder.h"
|
||||
#include "camel-imap-command.h"
|
||||
#include "camel-imap-store.h"
|
||||
#include "camel-imap-stream.h"
|
||||
#include "camel-imap-utils.h"
|
||||
@ -236,6 +237,7 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
CamelImapResponse *response;
|
||||
gint i, max;
|
||||
|
||||
if (expunge) {
|
||||
@ -249,20 +251,20 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
|
||||
for (i = 0; i < max; i++) {
|
||||
CamelMessageInfo *info;
|
||||
|
||||
info = (CamelMessageInfo *) g_ptr_array_index (imap_folder->summary, i);
|
||||
info = g_ptr_array_index (imap_folder->summary, i);
|
||||
if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) {
|
||||
char *flags;
|
||||
|
||||
flags = imap_create_flag_list (info->flags);
|
||||
if (flags) {
|
||||
gint s;
|
||||
|
||||
s = camel_imap_command_extended (store, folder, NULL, ex,
|
||||
"UID STORE %s FLAGS.SILENT %s",
|
||||
info->uid, flags);
|
||||
if (s != CAMEL_IMAP_OK)
|
||||
return;
|
||||
response = camel_imap_command (
|
||||
store, folder, ex,
|
||||
"UID STORE %s FLAGS.SILENT %s",
|
||||
info->uid, flags);
|
||||
g_free (flags);
|
||||
if (!response)
|
||||
return;
|
||||
camel_imap_response_free (response);
|
||||
}
|
||||
info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
|
||||
}
|
||||
@ -273,30 +275,32 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
|
||||
static void
|
||||
imap_expunge (CamelFolder *folder, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
|
||||
CamelImapResponse *response;
|
||||
|
||||
imap_sync (folder, FALSE, ex);
|
||||
camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, NULL, ex, "EXPUNGE");
|
||||
response = camel_imap_command (store, folder, ex, "EXPUNGE");
|
||||
camel_imap_response_free (response);
|
||||
}
|
||||
|
||||
static gint
|
||||
imap_get_message_count_internal (CamelFolder *folder, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
|
||||
gchar *result, *msg_count, *folder_path;
|
||||
GPtrArray *response;
|
||||
gint status, count = 0;
|
||||
char *result, *msg_count, *folder_path;
|
||||
CamelImapResponse *response;
|
||||
int count = 0;
|
||||
|
||||
folder_path = camel_imap_store_folder_path (store, folder->full_name);
|
||||
|
||||
if (store->has_status_capability)
|
||||
status = camel_imap_command_extended (store, folder, &response, ex,
|
||||
"STATUS \"%s\" (MESSAGES)", folder_path);
|
||||
response = camel_imap_command (store, folder, ex,
|
||||
"STATUS \"%s\" (MESSAGES)",
|
||||
folder_path);
|
||||
else
|
||||
status = camel_imap_command_extended (store, folder, &response, ex,
|
||||
"EXAMINE \"%s\"", folder_path);
|
||||
|
||||
response = camel_imap_command (store, folder, ex,
|
||||
"EXAMINE \"%s\"", folder_path);
|
||||
g_free (folder_path);
|
||||
|
||||
if (status != CAMEL_IMAP_OK)
|
||||
if (!response)
|
||||
return 0;
|
||||
|
||||
/* parse out the message count */
|
||||
@ -368,14 +372,16 @@ imap_get_unread_message_count (CamelFolder *folder)
|
||||
}
|
||||
|
||||
static void
|
||||
imap_append_message (CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, CamelException *ex)
|
||||
imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
|
||||
const CamelMessageInfo *info, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
|
||||
CamelImapResponse *response;
|
||||
CamelStream *memstream;
|
||||
CamelMimeFilter *crlf_filter;
|
||||
CamelStreamFilter *streamfilter;
|
||||
GByteArray *ba;
|
||||
gchar *cmdid;
|
||||
gchar *folder_path, *flagstr;
|
||||
gint status;
|
||||
char *folder_path, *flagstr, *result;
|
||||
|
||||
folder_path = camel_imap_store_folder_path (store, folder->full_name);
|
||||
|
||||
@ -384,74 +390,83 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message, const Camel
|
||||
flagstr = imap_create_flag_list (info->flags);
|
||||
else
|
||||
flagstr = NULL;
|
||||
|
||||
|
||||
/* FIXME: We could avoid this if we knew how big the message was. */
|
||||
memstream = camel_stream_mem_new ();
|
||||
ba = g_byte_array_new ();
|
||||
memstream = camel_stream_mem_new_with_byte_array (ba);
|
||||
/* FIXME: we need to crlf/dot filter */
|
||||
camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), memstream);
|
||||
camel_stream_write_string (memstream, "\r\n");
|
||||
camel_stream_reset (memstream);
|
||||
|
||||
status = camel_imap_command_preliminary (store, &cmdid, ex, "APPEND %s%s%s {%d}",
|
||||
folder_path, flagstr ? " " : "",
|
||||
flagstr ? flagstr : "", ba->len - 2);
|
||||
camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (memstream), ba);
|
||||
|
||||
streamfilter = camel_stream_filter_new_with_stream (memstream);
|
||||
crlf_filter = camel_mime_filter_crlf_new (
|
||||
CAMEL_MIME_FILTER_CRLF_ENCODE,
|
||||
CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
|
||||
camel_stream_filter_add (streamfilter, crlf_filter);
|
||||
camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message),
|
||||
CAMEL_STREAM (streamfilter));
|
||||
camel_object_unref (CAMEL_OBJECT (streamfilter));
|
||||
camel_object_unref (CAMEL_OBJECT (crlf_filter));
|
||||
camel_object_unref (CAMEL_OBJECT (memstream));
|
||||
|
||||
response = camel_imap_command (store, NULL, ex, "APPEND %s%s%s {%d}",
|
||||
folder_path, flagstr ? " " : "",
|
||||
flagstr ? flagstr : "", ba->len);
|
||||
g_free (folder_path);
|
||||
g_free (flagstr);
|
||||
|
||||
if (status != CAMEL_IMAP_PLUS) {
|
||||
g_free (cmdid);
|
||||
camel_object_unref (CAMEL_OBJECT (memstream));
|
||||
if (!response) {
|
||||
g_byte_array_free (ba, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* send the rest of our data - the mime message */
|
||||
status = camel_imap_command_continuation_with_stream (store, NULL, cmdid, memstream, ex);
|
||||
g_free (cmdid);
|
||||
|
||||
if (status != CAMEL_IMAP_OK)
|
||||
result = camel_imap_response_extract_continuation (response, ex);
|
||||
if (!result) {
|
||||
g_byte_array_free (ba, TRUE);
|
||||
return;
|
||||
|
||||
camel_object_unref (CAMEL_OBJECT (memstream));
|
||||
camel_imap_folder_changed (folder, 1, NULL, ex);
|
||||
}
|
||||
g_free (result);
|
||||
|
||||
/* send the rest of our data - the mime message */
|
||||
g_byte_array_append (ba, "\0", 3);
|
||||
response = camel_imap_command_continuation (store, ex, ba->data);
|
||||
g_byte_array_free (ba, TRUE);
|
||||
if (!response)
|
||||
return;
|
||||
camel_imap_response_free (response);
|
||||
}
|
||||
|
||||
static void
|
||||
imap_copy_message_to (CamelFolder *source, const char *uid, CamelFolder *destination, CamelException *ex)
|
||||
imap_copy_message_to (CamelFolder *source, const char *uid,
|
||||
CamelFolder *destination, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
|
||||
CamelImapResponse *response;
|
||||
char *folder_path;
|
||||
int status;
|
||||
|
||||
folder_path = camel_imap_store_folder_path (store, destination->full_name);
|
||||
status = camel_imap_command_extended (store, source, NULL, ex,
|
||||
"UID COPY %s %s", uid, folder_path);
|
||||
response = camel_imap_command (store, source, ex, "UID COPY %s %s",
|
||||
uid, folder_path);
|
||||
camel_imap_response_free (response);
|
||||
g_free (folder_path);
|
||||
|
||||
if (status != CAMEL_IMAP_OK)
|
||||
return;
|
||||
|
||||
camel_imap_folder_changed (destination, 1, NULL, ex);
|
||||
}
|
||||
|
||||
/* FIXME: Duplication of code! */
|
||||
static void
|
||||
imap_move_message_to (CamelFolder *source, const char *uid, CamelFolder *destination, CamelException *ex)
|
||||
imap_move_message_to (CamelFolder *source, const char *uid,
|
||||
CamelFolder *destination, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
|
||||
CamelImapResponse *response;
|
||||
char *folder_path;
|
||||
int status;
|
||||
|
||||
|
||||
folder_path = camel_imap_store_folder_path (store, destination->full_name);
|
||||
status = camel_imap_command_extended (store, source, NULL, ex,
|
||||
"UID COPY %s %s", uid, folder_path);
|
||||
response = camel_imap_command (store, source, ex, "UID COPY %s %s",
|
||||
uid, folder_path);
|
||||
camel_imap_response_free (response);
|
||||
g_free (folder_path);
|
||||
|
||||
if (status != CAMEL_IMAP_OK)
|
||||
|
||||
if (camel_exception_is_set (ex))
|
||||
return;
|
||||
|
||||
|
||||
camel_folder_delete_message (source, uid);
|
||||
|
||||
camel_imap_folder_changed (destination, 1, NULL, ex);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
@ -480,142 +495,41 @@ static CamelMimeMessage *
|
||||
imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
|
||||
CamelStream *msgstream = NULL;
|
||||
CamelMimeMessage *msg = NULL;
|
||||
gchar *result, *header, *body, *mesg, *p, *q, *data_item;
|
||||
int status, part_len;
|
||||
|
||||
if (store->server_level >= IMAP_LEVEL_IMAP4REV1)
|
||||
data_item = "BODY.PEEK[HEADER]";
|
||||
else
|
||||
data_item = "RFC822.HEADER";
|
||||
|
||||
status = camel_imap_fetch_command (store, folder, &result, ex,
|
||||
"UID FETCH %s %s", uid, data_item);
|
||||
|
||||
if (!result || status != CAMEL_IMAP_OK)
|
||||
CamelImapResponse *response;
|
||||
CamelStream *msgstream;
|
||||
CamelMimeMessage *msg;
|
||||
char *result, *mesg, *p;
|
||||
int len;
|
||||
|
||||
response = camel_imap_command (store, folder, ex,
|
||||
"UID FETCH %s RFC822", uid);
|
||||
if (!response)
|
||||
return NULL;
|
||||
|
||||
/* parse out the message part */
|
||||
for (p = result; *p && *p != '{' && *p != '"' && *p != '\n'; p++);
|
||||
switch (*p) {
|
||||
case '"':
|
||||
/* a quoted string - section 4.3 */
|
||||
p++;
|
||||
for (q = p; *q && *q != '"' && *q != '\n'; q++);
|
||||
part_len = (gint) (q - p);
|
||||
|
||||
break;
|
||||
case '{':
|
||||
/* a literal string - section 4.3 */
|
||||
part_len = atoi (p + 1);
|
||||
for ( ; *p && *p != '\n'; p++);
|
||||
if (*p != '\n') {
|
||||
g_free (result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* advance to the beginning of the actual data */
|
||||
p++;
|
||||
|
||||
/* calculate the new part-length */
|
||||
for (q = p; *q && (q - p) <= part_len; q++) {
|
||||
if (*q == '\n')
|
||||
part_len--;
|
||||
}
|
||||
|
||||
/* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
|
||||
for ( ; q > p && *(q-1) != '\n'; q--, part_len--);
|
||||
part_len++;
|
||||
|
||||
break;
|
||||
default:
|
||||
/* Bad input */
|
||||
result = camel_imap_response_extract (response, "FETCH", ex);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
p = strstr (result, "RFC822");
|
||||
if (p) {
|
||||
p += 7;
|
||||
mesg = imap_parse_nstring (&p, &len);
|
||||
}
|
||||
if (!p) {
|
||||
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
|
||||
"Could not find message body in FETCH "
|
||||
"response.");
|
||||
g_free (result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
header = g_strndup (p, part_len);
|
||||
|
||||
g_free (result);
|
||||
d(fprintf (stderr, "*** We got the header ***\n"));
|
||||
|
||||
if (store->server_level >= IMAP_LEVEL_IMAP4REV1)
|
||||
data_item = "BODY[TEXT]";
|
||||
else
|
||||
data_item = "RFC822.TEXT";
|
||||
|
||||
status = camel_imap_fetch_command (store, folder, &result, ex,
|
||||
"UID FETCH %s %s", uid, data_item);
|
||||
|
||||
if (!result || status != CAMEL_IMAP_OK) {
|
||||
g_free (header);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* parse out the message part */
|
||||
for (p = result; *p && *p != '{' && *p != '"' && *p != '\n'; p++);
|
||||
switch (*p) {
|
||||
case '"':
|
||||
/* a quoted string - section 4.3 */
|
||||
p++;
|
||||
for (q = p; *q && *q != '"' && *q != '\n'; q++);
|
||||
part_len = (gint) (q - p);
|
||||
|
||||
break;
|
||||
case '{':
|
||||
/* a literal string - section 4.3 */
|
||||
part_len = atoi (p + 1);
|
||||
for ( ; *p && *p != '\n'; p++);
|
||||
if (*p != '\n') {
|
||||
g_free (result);
|
||||
g_free (header);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* advance to the beginning of the actual data */
|
||||
p++;
|
||||
|
||||
/* calculate the new part-length */
|
||||
for (q = p; *q && (q - p) <= part_len; q++) {
|
||||
if (*q == '\n')
|
||||
part_len--;
|
||||
}
|
||||
|
||||
/* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
|
||||
for ( ; q > p && *(q-1) != '\n'; q--, part_len--);
|
||||
part_len++;
|
||||
|
||||
break;
|
||||
default:
|
||||
/* Bad input */
|
||||
g_free (result);
|
||||
g_free (header);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
body = g_strndup (p, part_len);
|
||||
|
||||
g_free (result);
|
||||
d(fprintf (stderr, "*** We got the body ***\n"));
|
||||
|
||||
mesg = g_strdup_printf ("%s\n%s", header, body);
|
||||
g_free (header);
|
||||
g_free (body);
|
||||
d(fprintf (stderr, "*** We got the mesg ***\n"));
|
||||
|
||||
d(fprintf (stderr, "Message:\n%s\n", mesg));
|
||||
|
||||
msgstream = camel_stream_mem_new_with_buffer (mesg, strlen (mesg) + 1);
|
||||
|
||||
msgstream = camel_stream_mem_new_with_buffer (mesg, len);
|
||||
msg = camel_mime_message_new ();
|
||||
d(fprintf (stderr, "*** We created the camel_mime_message ***\n"));
|
||||
|
||||
camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), msgstream);
|
||||
camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg),
|
||||
msgstream);
|
||||
camel_object_unref (CAMEL_OBJECT (msgstream));
|
||||
|
||||
d(fprintf (stderr, "*** We're returning... ***\n"));
|
||||
|
||||
g_free (mesg);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
@ -673,7 +587,8 @@ imap_protocol_get_summary_specifier (CamelImapStore *store)
|
||||
sect_end = "";
|
||||
}
|
||||
|
||||
return g_strdup_printf ("UID FLAGS %s (%s)%s", sect_begin, headers_wanted, sect_end);
|
||||
return g_strdup_printf ("UID FLAGS %s (%s)%s", sect_begin,
|
||||
headers_wanted, sect_end);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
@ -682,10 +597,11 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
|
||||
/* This ALWAYS updates the summary except on fail */
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
CamelImapResponse *response;
|
||||
GPtrArray *summary = NULL, *headers = NULL;
|
||||
GHashTable *hash = NULL;
|
||||
gint num, i, j, status = 0;
|
||||
char *result, *q, *node;
|
||||
int num, i, j;
|
||||
char *q;
|
||||
const char *received;
|
||||
char *summary_specifier;
|
||||
struct _header_raw *h = NULL, *tail = NULL;
|
||||
@ -706,17 +622,18 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
|
||||
}
|
||||
|
||||
summary_specifier = imap_protocol_get_summary_specifier (store);
|
||||
|
||||
if (num == 1) {
|
||||
status = camel_imap_fetch_command (store, folder, &result, ex,
|
||||
"FETCH 1 (%s)", summary_specifier);
|
||||
response = camel_imap_command (store, folder, ex,
|
||||
"FETCH 1 (%s)",
|
||||
summary_specifier);
|
||||
} else {
|
||||
status = camel_imap_fetch_command (store, folder, &result, ex,
|
||||
"FETCH 1:%d (%s)", num, summary_specifier);
|
||||
response = camel_imap_command (store, folder, ex,
|
||||
"FETCH 1:%d (%s)", num,
|
||||
summary_specifier);
|
||||
}
|
||||
g_free (summary_specifier);
|
||||
|
||||
if (status != CAMEL_IMAP_OK) {
|
||||
if (!response) {
|
||||
if (!imap_folder->summary) {
|
||||
imap_folder->summary = g_ptr_array_new ();
|
||||
imap_folder->summary_hash = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
@ -724,32 +641,12 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
|
||||
|
||||
return imap_folder->summary;
|
||||
}
|
||||
|
||||
headers = response->untagged;
|
||||
|
||||
/* initialize our new summary-to-be */
|
||||
summary = g_ptr_array_new ();
|
||||
hash = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
/* create our array of headers from the server response */
|
||||
headers = g_ptr_array_new ();
|
||||
node = result;
|
||||
for (i = 1; node; i++) {
|
||||
char *end;
|
||||
|
||||
if ((end = strstr (node + 2, "\n*"))) {
|
||||
g_ptr_array_add (headers, g_strndup (node, (gint)(end - node)));
|
||||
} else {
|
||||
g_ptr_array_add (headers, g_strdup (node));
|
||||
}
|
||||
node = end;
|
||||
}
|
||||
if (i < num) {
|
||||
d(fprintf (stderr, "IMAP server didn't respond with as many headers as we expected...\n"));
|
||||
/* should we error?? */
|
||||
}
|
||||
|
||||
g_free (result);
|
||||
result = NULL;
|
||||
|
||||
for (i = 0; i < headers->len; i++) {
|
||||
CamelMessageInfo *info;
|
||||
char *uid, *flags, *header;
|
||||
@ -834,10 +731,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
|
||||
g_ptr_array_add (summary, info);
|
||||
g_hash_table_insert (hash, info->uid, info);
|
||||
}
|
||||
|
||||
for (i = 0; i < headers->len; i++)
|
||||
g_free (headers->pdata[i]);
|
||||
g_ptr_array_free (headers, TRUE);
|
||||
camel_imap_response_free (response);
|
||||
|
||||
/* clean up any previous summary data */
|
||||
imap_folder_summary_free (imap_folder);
|
||||
@ -861,22 +755,24 @@ static CamelMessageInfo *
|
||||
imap_get_message_info_internal (CamelFolder *folder, guint id, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
|
||||
CamelImapResponse *response;
|
||||
CamelMessageInfo *info = NULL;
|
||||
struct _header_raw *h, *tail = NULL;
|
||||
const char *received;
|
||||
char *result, *uid, *flags, *header, *q;
|
||||
char *summary_specifier;
|
||||
int j, status;
|
||||
int j;
|
||||
|
||||
/* we don't have a cached copy, so fetch it */
|
||||
summary_specifier = imap_protocol_get_summary_specifier (store);
|
||||
|
||||
status = camel_imap_fetch_command (store, folder, &result, ex,
|
||||
"FETCH %d (%s)", id, summary_specifier);
|
||||
|
||||
response = camel_imap_command (store, folder, ex,
|
||||
"FETCH %d (%s)", id, summary_specifier);
|
||||
g_free (summary_specifier);
|
||||
|
||||
if (status != CAMEL_IMAP_OK)
|
||||
|
||||
if (!response)
|
||||
return NULL;
|
||||
result = camel_imap_response_extract (response, "FETCH", ex);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
/* lets grab the UID... */
|
||||
@ -977,9 +873,9 @@ imap_get_message_info (CamelFolder *folder, const char *uid)
|
||||
static GPtrArray *
|
||||
imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
|
||||
{
|
||||
GPtrArray *response, *uids = NULL;
|
||||
CamelImapResponse *response;
|
||||
GPtrArray *uids = NULL;
|
||||
char *result, *sexp, *p;
|
||||
int status;
|
||||
|
||||
d(fprintf (stderr, "camel sexp: '%s'\n", expression));
|
||||
sexp = imap_translate_sexp (expression);
|
||||
@ -992,12 +888,12 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc
|
||||
return uids;
|
||||
}
|
||||
|
||||
status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder,
|
||||
&response, NULL, "UID SEARCH %s", sexp);
|
||||
response = camel_imap_command (CAMEL_IMAP_STORE (folder->parent_store),
|
||||
folder, NULL, "UID SEARCH %s", sexp);
|
||||
g_free (sexp);
|
||||
|
||||
if (status != CAMEL_IMAP_OK)
|
||||
if (!response)
|
||||
return uids;
|
||||
|
||||
result = camel_imap_response_extract (response, "SEARCH", NULL);
|
||||
if (!result)
|
||||
return uids;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -66,50 +66,6 @@ typedef struct {
|
||||
} CamelImapStoreClass;
|
||||
|
||||
|
||||
/* public methods */
|
||||
void camel_imap_store_open (CamelImapStore *store, CamelException *ex);
|
||||
void camel_imap_store_close (CamelImapStore *store, gboolean expunge, CamelException *ex);
|
||||
|
||||
/* support functions */
|
||||
|
||||
enum {
|
||||
CAMEL_IMAP_OK = 0,
|
||||
CAMEL_IMAP_NO,
|
||||
CAMEL_IMAP_BAD,
|
||||
CAMEL_IMAP_PLUS,
|
||||
CAMEL_IMAP_FAIL
|
||||
};
|
||||
|
||||
gint camel_imap_command (CamelImapStore *store, CamelFolder *folder,
|
||||
CamelException *ex, char *fmt, ...);
|
||||
|
||||
gint camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder,
|
||||
GPtrArray **ret, CamelException *ex, char *fmt, ...);
|
||||
void camel_imap_response_free (GPtrArray *response);
|
||||
char *camel_imap_response_extract (GPtrArray *response, const char *type,
|
||||
CamelException *ex);
|
||||
|
||||
gint camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder,
|
||||
char **ret, CamelException *ex, char *fmt, ...);
|
||||
|
||||
/* multi-transactional commands... */
|
||||
gint camel_imap_command_preliminary (CamelImapStore *store,
|
||||
char **cmdid,
|
||||
CamelException *ex,
|
||||
char *fmt, ...);
|
||||
|
||||
gint camel_imap_command_continuation (CamelImapStore *store,
|
||||
char **ret,
|
||||
char *cmdid,
|
||||
char *cmdbuf,
|
||||
CamelException *ex);
|
||||
|
||||
gint camel_imap_command_continuation_with_stream (CamelImapStore *store,
|
||||
char **ret,
|
||||
char *cmdid,
|
||||
CamelStream *cstream,
|
||||
CamelException *ex);
|
||||
|
||||
/* Standard Camel function */
|
||||
CamelType camel_imap_store_get_type (void);
|
||||
|
||||
|
||||
@ -558,3 +558,77 @@ imap_parse_flag_list (const char *flag_list)
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* imap_parse_nstring:
|
||||
* @str_p: a pointer to a string
|
||||
* @len: a pointer to an int to return the length in
|
||||
*
|
||||
* This parses an "nstring" (NIL, a quoted string, or a literal)
|
||||
* starting at *@str_p. On success, *@str_p will point to the first
|
||||
* character after the end of the nstring, and *@len will contain
|
||||
* the length of the returned string. On failure, *@str_p will be
|
||||
* set to %NULL.
|
||||
*
|
||||
* This assumes that the string is in the form returned by
|
||||
* camel_imap_command(): that line breaks are indicated by LF rather
|
||||
* than CRLF.
|
||||
*
|
||||
* Return value: the parsed string, or %NULL if a NIL or no string
|
||||
* was parsed. (In the former case, *@str_p will be %NULL; in the
|
||||
* latter, it will point to the character after the NIL.)
|
||||
**/
|
||||
char *
|
||||
imap_parse_nstring (char **str_p, int *len)
|
||||
{
|
||||
char *str = *str_p;
|
||||
char *out;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
else if (*str == '"') {
|
||||
char *p;
|
||||
int size;
|
||||
|
||||
str++;
|
||||
size = strcspn (str, "\"") + 1;
|
||||
p = out = g_malloc (size);
|
||||
|
||||
while (*str && *str != '"') {
|
||||
if (*str == '\\')
|
||||
str++;
|
||||
*p++ = *str++;
|
||||
if (p - out == size) {
|
||||
out = g_realloc (out, size * 2);
|
||||
p = out + size;
|
||||
size *= 2;
|
||||
}
|
||||
}
|
||||
if (*str != '"') {
|
||||
*str_p = NULL;
|
||||
g_free (out);
|
||||
return NULL;
|
||||
}
|
||||
*p = '\0';
|
||||
*str_p = str + 1;
|
||||
*len = strlen (out);
|
||||
return out;
|
||||
} else if (*str == '{') {
|
||||
*len = strtoul (str + 1, (char **)&str, 10);
|
||||
if (*str++ != '}' || *str++ != '\n' || strlen (str) < *len) {
|
||||
*str_p = NULL;
|
||||
return NULL;
|
||||
}
|
||||
out = g_strndup (str, *len);
|
||||
*str_p = str + *len;
|
||||
return out;
|
||||
} else if (!g_strncasecmp (str, "nil", 3)) {
|
||||
*str_p += 3;
|
||||
*len = 0;
|
||||
return NULL;
|
||||
} else {
|
||||
*str_p = NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,8 @@ char *imap_translate_sexp (const char *expression);
|
||||
char *imap_create_flag_list (guint32 flags);
|
||||
guint32 imap_parse_flag_list (const char *flag_list);
|
||||
|
||||
char *imap_parse_nstring (char **str_p, int *len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
Reference in New Issue
Block a user