aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog28
-rw-r--r--camel/providers/nntp/camel-nntp-newsrc.c32
-rw-r--r--camel/providers/nntp/camel-nntp-store.c184
-rw-r--r--camel/providers/nntp/camel-nntp-store.h31
-rw-r--r--camel/providers/nntp/camel-nntp-utils.c56
5 files changed, 294 insertions, 37 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 4c3a60d500..410a5dfaf8 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,31 @@
+2000-08-31 Chris Toshok <toshok@helixcode.com>
+
+ * providers/nntp/camel-nntp-newsrc.c
+ (camel_nntp_newsrc_read_for_server): make this a bit more robust.
+ try to create an empty .newsrc file for the server if we can't
+ open it for reading. also, don't allocate everything until we've
+ opened the file.
+
+ * providers/nntp/camel-nntp-utils.c (get_OVER_headers): make use
+ of our overview field indices.
+ (camel_nntp_get_headers): only call get_OVER_headers if the
+ extension is present. warn if it's not - since get_HEAD_headers
+ needs work before it works.
+
+ * providers/nntp/camel-nntp-store.c
+ (camel_nntp_store_get_extensions): new function - query the server
+ for it's extensions.
+ (camel_nntp_store_get_overview_fmt): new function - query the
+ server for the overview format and build our table of the indices
+ we care about. support the "full" suffix on fields.
+ (nntp_store_connect): call camel_nntp_store_get_extensions and
+ camel_nntp_store_get_overview_fmt.
+
+ * providers/nntp/camel-nntp-store.h: add codes for extensions
+ found on news.mozilla.org. only one that we care about is OVER.
+ also, add CamelNNTPOverField and an enum of the overview fields
+ that we care about.
+
2000-08-31 Jeffrey Stedfast <fejj@helixcode.com>
* providers/imap/camel-imap-utils.c (imap_translate_sexp):
diff --git a/camel/providers/nntp/camel-nntp-newsrc.c b/camel/providers/nntp/camel-nntp-newsrc.c
index 81594d3dcd..9510fe5bfa 100644
--- a/camel/providers/nntp/camel-nntp-newsrc.c
+++ b/camel/providers/nntp/camel-nntp-newsrc.c
@@ -26,6 +26,8 @@
#include <string.h>
#include <stdlib.h>
#include <glib.h>
+#include <fcntl.h>
+#include <unistd.h>
#include "camel-nntp-newsrc.h"
typedef struct {
@@ -440,17 +442,33 @@ camel_nntp_newsrc_read_for_server (const char *server)
{
FILE *fp;
char buf[BUFFER_LENGTH];
- CamelNNTPNewsrc *newsrc = g_new0(CamelNNTPNewsrc, 1);
+ char *filename = g_strdup_printf ("%s/.newsrc-%s", g_get_home_dir(), server);
+ CamelNNTPNewsrc *newsrc;
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ int fd;
+
+ g_warning ("~/.newsrc-%s not present. creating empty file\n", server);
+
+ if ((fd = open (filename, O_CREAT, O_TRUNC, O_WRONLY, 0777)) < 0) {
+ g_warning ("unable to create ~/.newsrc-%s file\n", server);
+ g_free (filename);
+ return NULL;
+ }
+ close (fd);
- newsrc->filename = g_strdup_printf ("%s/.newsrc-%s", g_get_home_dir(), server);
+ if ((fp = fopen(filename, "r")) == NULL) {
+ g_warning ("unable to open ~/.newsrc-%s file on second try.\n", server);
+ g_free (filename);
+ return NULL;
+ }
+ }
+
+ newsrc = g_new0(CamelNNTPNewsrc, 1);
+ newsrc->filename = filename;
newsrc->groups = g_hash_table_new (g_str_hash, g_str_equal);
newsrc->subscribed_groups = g_hash_table_new (g_str_hash, g_str_equal);
- if ((fp = fopen(newsrc->filename, "r")) == NULL) {
- g_free (newsrc->filename);
- g_free (newsrc);
- return NULL;
- }
while (fgets(buf, MAX_LINE_LENGTH, fp) != NULL) {
/* we silently ignore (and lose!) lines longer than 20 * 1500 chars.
diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c
index 5c9475ed14..37cb184f28 100644
--- a/camel/providers/nntp/camel-nntp-store.c
+++ b/camel/providers/nntp/camel-nntp-store.c
@@ -48,6 +48,8 @@
#define NNTP_PORT 119
+#define DUMP_EXTENSIONS
+
static CamelServiceClass *service_class = NULL;
/* Returns the class for a CamelNNTPStore */
@@ -57,6 +59,143 @@ static CamelServiceClass *service_class = NULL;
static gboolean ensure_news_dir_exists (CamelNNTPStore *store);
+static void
+camel_nntp_store_get_extensions (CamelNNTPStore *store)
+{
+ store->extensions = 0;
+
+ if (CAMEL_NNTP_OK == camel_nntp_command (store, NULL, "LIST EXTENSIONS")) {
+ gboolean done = FALSE;
+
+ while (!done) {
+ char *line;
+
+ line = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER(store->istream));
+
+ if (*line == '.') {
+ done = TRUE;
+ }
+ else {
+#define CHECK_EXT(name,val) if (!strcasecmp (line, (name))) store->extensions |= (val)
+
+ CHECK_EXT ("SEARCH", CAMEL_NNTP_EXT_SEARCH);
+ CHECK_EXT ("SETGET", CAMEL_NNTP_EXT_SETGET);
+ CHECK_EXT ("OVER", CAMEL_NNTP_EXT_OVER);
+ CHECK_EXT ("XPATTEXT", CAMEL_NNTP_EXT_XPATTEXT);
+ CHECK_EXT ("XACTIVE", CAMEL_NNTP_EXT_XACTIVE);
+ CHECK_EXT ("LISTMOTD", CAMEL_NNTP_EXT_LISTMOTD);
+ CHECK_EXT ("LISTSUBSCR", CAMEL_NNTP_EXT_LISTSUBSCR);
+ CHECK_EXT ("LISTPNAMES", CAMEL_NNTP_EXT_LISTPNAMES);
+
+#undef CHECK_EXT
+ }
+
+ g_free (line);
+ }
+ }
+
+#ifdef DUMP_EXTENSIONS
+ g_print ("NNTP Extensions:");
+#define DUMP_EXT(name,val) if (store->extensions & (val)) g_print (" %s", name);
+ DUMP_EXT ("SEARCH", CAMEL_NNTP_EXT_SEARCH);
+ DUMP_EXT ("SETGET", CAMEL_NNTP_EXT_SETGET);
+ DUMP_EXT ("OVER", CAMEL_NNTP_EXT_OVER);
+ DUMP_EXT ("XPATTEXT", CAMEL_NNTP_EXT_XPATTEXT);
+ DUMP_EXT ("XACTIVE", CAMEL_NNTP_EXT_XACTIVE);
+ DUMP_EXT ("LISTMOTD", CAMEL_NNTP_EXT_LISTMOTD);
+ DUMP_EXT ("LISTSUBSCR", CAMEL_NNTP_EXT_LISTSUBSCR);
+ DUMP_EXT ("LISTPNAMES", CAMEL_NNTP_EXT_LISTPNAMES);
+ g_print ("\n");
+#undef DUMP_EXT
+#endif
+}
+
+static void
+camel_nntp_store_get_overview_fmt (CamelNNTPStore *store)
+{
+ int status;
+ char *result;
+ char *field;
+ int i;
+
+ status = camel_nntp_command (store, NULL,
+ "LIST OVERVIEW.FMT");
+
+ if (status != CAMEL_NNTP_OK) {
+ /* if we can't get the overview format, we should
+ disable OVER support */
+ g_warning ("server reported support of OVER but LIST OVERVIEW.FMT failed."
+ " disabling OVER\n");
+ store->extensions &= ~CAMEL_NNTP_EXT_OVER;
+ return;
+ }
+
+ result = camel_nntp_command_get_additional_data (store);
+
+ /* count the number of fields the server returns in the
+ overview. start at 1 because the article number is always
+ first */
+ store->num_overview_fields = 1;
+
+ for (i = 0; i < CAMEL_NNTP_OVER_LAST; i ++) {
+ store->overview_field [i].index = -1;
+ }
+
+ while ((field = strsep (&result, "\n"))) {
+ CamelNNTPOverField *over_field = NULL;
+ char *colon = NULL;;
+
+ if (field[0] == '\0')
+ break;
+
+ if (!strncasecmp (field, "From:", 5)) {
+ over_field = &store->overview_field [ CAMEL_NNTP_OVER_FROM ];
+ over_field->index = store->num_overview_fields;
+ colon = field + 5;
+ }
+ else if (!strncasecmp (field, "Subject:", 7)) {
+ over_field = &store->overview_field [ CAMEL_NNTP_OVER_SUBJECT ];
+ over_field->index = store->num_overview_fields;
+ colon = field + 7;
+ }
+ else if (!strncasecmp (field, "Date:", 5)) {
+ over_field = &store->overview_field [ CAMEL_NNTP_OVER_DATE ];
+ over_field->index = store->num_overview_fields;
+ colon = field + 5;
+ }
+ else if (!strncasecmp (field, "Message-ID:", 11)) {
+ over_field = &store->overview_field [ CAMEL_NNTP_OVER_MESSAGE_ID ];
+ over_field->index = store->num_overview_fields;
+ colon = field + 11;
+ }
+ else if (!strncasecmp (field, "References:", 11)) {
+ over_field = &store->overview_field [ CAMEL_NNTP_OVER_REFERENCES ];
+ over_field->index = store->num_overview_fields;
+ colon = field + 11;
+ }
+ else if (!strncasecmp (field, "Bytes:", 6)) {
+ over_field = &store->overview_field [ CAMEL_NNTP_OVER_BYTES ];
+ over_field->index = store->num_overview_fields;
+ colon = field + 11;
+ }
+
+ if (colon && !strcmp (colon + 1, "full"))
+ over_field->full = TRUE;
+
+ store->num_overview_fields ++;
+ }
+
+ g_free (result);
+
+ for (i = 0; i < CAMEL_NNTP_OVER_LAST; i ++) {
+ if (store->overview_field [i].index == -1) {
+ g_warning ("server's OVERVIEW.FMT doesn't support minimum set we require,"
+ " disabling OVER support.\n");
+ store->extensions &= ~CAMEL_NNTP_EXT_OVER;
+ }
+ }
+}
+
static gboolean
nntp_store_connect (CamelService *service, CamelException *ex)
{
@@ -64,6 +203,7 @@ nntp_store_connect (CamelService *service, CamelException *ex)
struct sockaddr_in sin;
int fd;
char *buf;
+ int resp_code;
CamelNNTPStore *store = CAMEL_NNTP_STORE (service);
if (!ensure_news_dir_exists(store)) {
@@ -106,14 +246,29 @@ nntp_store_connect (CamelService *service, CamelException *ex)
return -1;
}
+ /* check if posting is allowed. */
+ resp_code = atoi (buf);
+ if (resp_code == 200) {
+ g_print ("posting allowed\n");
+ store->posting_allowed = TRUE;
+ }
+ else if (resp_code == 201) {
+ g_print ("no posting allowed\n");
+ store->posting_allowed = FALSE;
+ }
+ else {
+ g_warning ("unexpected server greeting code %d, no posting allowed\n", resp_code);
+ store->posting_allowed = FALSE;
+ }
+
g_free (buf);
/* get a list of extensions that the server supports */
- if (CAMEL_NNTP_OK == camel_nntp_command (store, NULL, "LIST EXTENSIONS")) {
- char *ext_response = camel_nntp_command_get_additional_data(store);
+ camel_nntp_store_get_extensions (store);
- g_free (ext_response);
- }
+ /* if the server supports the OVER extension, get the overview.fmt */
+ if (store->extensions & CAMEL_NNTP_EXT_OVER)
+ camel_nntp_store_get_overview_fmt (store);
return TRUE;
}
@@ -162,6 +317,14 @@ nntp_store_get_folder (CamelStore *store, const gchar *folder_name,
nntp_store->newsrc =
camel_nntp_newsrc_read_for_server (CAMEL_SERVICE(store)->url->host);
+ if (!nntp_store->newsrc) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ "Unable to open or create .newsrc file for %s: %s",
+ CAMEL_SERVICE(store)->url->host,
+ strerror(errno));
+ return NULL;
+ }
+
/* check if folder has already been created */
/* call the standard routine for that when */
/* it is done ... */
@@ -329,13 +492,12 @@ camel_nntp_command (CamelNNTPStore *store, char **ret, char *fmt, ...)
* a NNTP command.
* @store: the NNTP store
*
- * This command gets the additional data returned by
- * This command gets the additional data returned by "multi-line" POP
- * commands, such as LIST, RETR, TOP, and UIDL. This command _must_
- * be called after a successful (CAMEL_NNTP_OK) call to
- * camel_nntp_command for a command that has a multi-line response.
- * The returned data is un-byte-stuffed, and has lines termined by
- * newlines rather than CR/LF pairs.
+ * This command gets the additional data returned by This command gets
+ * the additional data returned by "multi-line" NNTP commands, such as
+ * LIST. This command must only be called after a successful
+ * (CAMEL_NNTP_OK) call to camel_nntp_command for a command that has a
+ * multi-line response. The returned data is un-byte-stuffed, and has
+ * lines termined by newlines rather than CR/LF pairs.
*
* Return value: the data, which the caller must free.
**/
diff --git a/camel/providers/nntp/camel-nntp-store.h b/camel/providers/nntp/camel-nntp-store.h
index 3099f84962..a74ea84f5e 100644
--- a/camel/providers/nntp/camel-nntp-store.h
+++ b/camel/providers/nntp/camel-nntp-store.h
@@ -40,12 +40,41 @@ extern "C" {
#define IS_CAMEL_NNTP_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_NNTP_STORE_TYPE))
+enum {
+ CAMEL_NNTP_OVER_FROM,
+ CAMEL_NNTP_OVER_SUBJECT,
+ CAMEL_NNTP_OVER_DATE,
+ CAMEL_NNTP_OVER_MESSAGE_ID,
+ CAMEL_NNTP_OVER_REFERENCES,
+ CAMEL_NNTP_OVER_BYTES,
+
+ CAMEL_NNTP_OVER_LAST
+};
+
+typedef struct {
+ int index;
+ gboolean full; /* full in the OVER sense - the field name
+ precedes the ':' in the XOVER list. */
+} CamelNNTPOverField;
+
typedef struct {
CamelStore parent_object;
-#define CAMEL_NNTP_EXT_XOVER 0x01
+#define CAMEL_NNTP_EXT_SEARCH (1<<0)
+#define CAMEL_NNTP_EXT_SETGET (1<<1)
+#define CAMEL_NNTP_EXT_OVER (1<<2)
+#define CAMEL_NNTP_EXT_XPATTEXT (1<<3)
+#define CAMEL_NNTP_EXT_XACTIVE (1<<4)
+#define CAMEL_NNTP_EXT_LISTMOTD (1<<5)
+#define CAMEL_NNTP_EXT_LISTSUBSCR (1<<6)
+#define CAMEL_NNTP_EXT_LISTPNAMES (1<<7)
guint32 extensions;
+ gboolean posting_allowed;
+
+ int num_overview_fields;
+ CamelNNTPOverField overview_field[ CAMEL_NNTP_OVER_LAST ];
+
CamelNNTPNewsrc *newsrc;
CamelStream *istream, *ostream;
diff --git a/camel/providers/nntp/camel-nntp-utils.c b/camel/providers/nntp/camel-nntp-utils.c
index e0a331f2a7..01b7876134 100644
--- a/camel/providers/nntp/camel-nntp-utils.c
+++ b/camel/providers/nntp/camel-nntp-utils.c
@@ -33,7 +33,7 @@
#include <string.h>
static void
-get_XOVER_headers(CamelNNTPStore *nntp_store, CamelFolder *folder,
+get_OVER_headers(CamelNNTPStore *nntp_store, CamelFolder *folder,
int first_message, int last_message, CamelException *ex)
{
int status;
@@ -43,7 +43,7 @@ get_XOVER_headers(CamelNNTPStore *nntp_store, CamelFolder *folder,
"XOVER %d-%d",
first_message,
last_message);
-
+
if (status == CAMEL_NNTP_OK) {
CamelStream *nntp_istream = nntp_store->istream;
gboolean done = FALSE;
@@ -55,23 +55,44 @@ get_XOVER_headers(CamelNNTPStore *nntp_store, CamelFolder *folder,
if (*line == '.') {
done = TRUE;
+ g_print ("done\n");
}
else {
CamelMessageInfo *new_info = g_new0(CamelMessageInfo, 1);
char **split_line = g_strsplit (line, "\t", 7);
-
- new_info->subject = g_strdup(split_line[1]);
- new_info->from = g_strdup(split_line[2]);
+ char *subject, *from, *date, *message_id, *bytes;
+
+ subject = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_SUBJECT].index];
+ from = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_FROM].index];
+ date = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_DATE].index];
+ message_id = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_MESSAGE_ID].index];
+ bytes = split_line [nntp_store->overview_field [CAMEL_NNTP_OVER_BYTES].index];
+
+ /* if the overview format flagged this
+ field as "full", skip over the
+ preceding field name and colon */
+ if (nntp_store->overview_field [ CAMEL_NNTP_OVER_SUBJECT ].full)
+ subject += strlen ("Subject:");
+ if (nntp_store->overview_field [ CAMEL_NNTP_OVER_FROM ].full)
+ from += strlen ("From:");
+ if (nntp_store->overview_field [ CAMEL_NNTP_OVER_DATE ].full)
+ date += strlen ("Date:");
+ if (nntp_store->overview_field [ CAMEL_NNTP_OVER_MESSAGE_ID ].full)
+ message_id += strlen ("Message-ID:");
+ if (nntp_store->overview_field [ CAMEL_NNTP_OVER_BYTES ].full)
+ bytes += strlen ("Bytes:");
+
+ new_info->subject = g_strdup(subject);
+ new_info->from = g_strdup(from);
new_info->to = g_strdup(nntp_folder->group_name);
- new_info->date_sent = header_decode_date(split_line[3], NULL);
+ new_info->date_sent = header_decode_date(date, NULL);
#if 0
/* XXX do we need to fill in both dates? */
- new_info->headers.date_received = g_strdup(split_line[3]);
+ new_info->headers.date_received = g_strdup(date);
#endif
- new_info->size = atoi(split_line[5]);
- new_info->uid = g_strdup_printf ("%s,%s", split_line[0], split_line[4]);
- new_info->message_id = g_strdup(split_line[4]);
- g_strfreev (split_line);
+ new_info->size = atoi(bytes);
+ new_info->uid = g_strdup_printf ("%s,%s", split_line[0], message_id);
+ new_info->message_id = g_strdup(message_id);
if (camel_nntp_newsrc_article_is_read (nntp_store->newsrc,
nntp_folder->group_name,
@@ -79,6 +100,7 @@ get_XOVER_headers(CamelNNTPStore *nntp_store, CamelFolder *folder,
new_info->flags |= CAMEL_MESSAGE_SEEN;
camel_folder_summary_add (nntp_folder->summary, new_info);
+ g_strfreev (split_line);
}
g_free (line);
}
@@ -204,15 +226,13 @@ camel_nntp_get_headers (CamelStore *store,
return;
}
-#if 0
- if (nntp_store->extensions & CAMEL_NNTP_EXT_XOVER) {
-#endif
- get_XOVER_headers (nntp_store, folder, first_message, last_message, ex);
-#if 0
+ if (nntp_store->extensions & CAMEL_NNTP_EXT_OVER) {
+ get_OVER_headers (nntp_store, folder, first_message, last_message, ex);
}
else {
+ g_warning ("need to fix get_HEAD_headers\n");
+#if 0
get_HEAD_headers (nntp_store, folder, first_message, last_message, ex);
- }
#endif
+ }
}
-