/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2005 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: feeddriver.c,v 1.1 2007/01/18 09:15:01 hoa Exp $
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "feeddriver.h"
#include <string.h>
#include <stdlib.h>
#include "mailimf_types_helper.h"
#include "newsfeed.h"
#include "mail.h"
#include "mailmessage.h"
#include "maildriver_tools.h"
#include "feeddriver_message.h"
#include "feeddriver_types.h"
#define MIN_DELAY 5
static int feeddriver_initialize(mailsession * session);
static void feeddriver_uninitialize(mailsession * session);
static int feeddriver_connect_path(mailsession * session, const char * path);
static int feeddriver_status_folder(mailsession * session, const char * mb,
uint32_t * result_messages,
uint32_t * result_recent,
uint32_t * result_unseen);
static int feeddriver_messages_number(mailsession * session, const char * mb,
uint32_t * result);
static int
feeddriver_get_envelopes_list(mailsession * session,
struct mailmessage_list * env_list);
static int feeddriver_get_messages_list(mailsession * session,
struct mailmessage_list ** result);
static int feeddriver_get_message(mailsession * session,
uint32_t num, mailmessage ** result);
static int feeddriver_get_message_by_uid(mailsession * session,
const char * uid,
mailmessage ** result);
static mailsession_driver local_feed_session_driver = {
/* sess_name */ "feed",
/* sess_initialize */ feeddriver_initialize,
/* sess_uninitialize */ feeddriver_uninitialize,
/* sess_parameters */ NULL,
/* sess_connect_stream */ NULL,
/* sess_connect_path */ feeddriver_connect_path,
/* sess_starttls */ NULL,
/* sess_login */ NULL,
/* sess_logout */ NULL,
/* sess_noop */ NULL,
/* sess_build_folder_name */ NULL,
/* sess_create_folder */ NULL,
/* sess_delete_folder */ NULL,
/* sess_rename_folder */ NULL,
/* sess_check_folder */ NULL,
/* sess_examine_folder */ NULL,
/* sess_select_folder */ NULL,
/* sess_expunge_folder */ NULL,
/* sess_status_folder */ feeddriver_status_folder,
/* sess_messages_number */ feeddriver_messages_number,
/* sess_recent_number */ feeddriver_messages_number,
/* sess_unseen_number */ feeddriver_messages_number,
/* sess_list_folders */ NULL,
/* sess_lsub_folders */ NULL,
/* sess_subscribe_folder */ NULL,
/* sess_unsubscribe_folder */ NULL,
/* sess_append_message */ NULL,
/* sess_append_message_flags */ NULL,
/* sess_copy_message */ NULL,
/* sess_move_message */ NULL,
/* sess_get_message */ feeddriver_get_message,
/* sess_get_message_by_uid */ feeddriver_get_message_by_uid,
/* sess_get_messages_list */ feeddriver_get_messages_list,
/* sess_get_envelopes_list */ feeddriver_get_envelopes_list,
/* sess_remove_message */ NULL,
/* sess_login_sasl */ NULL,
};
mailsession_driver * feed_session_driver = &local_feed_session_driver;
static void update(mailsession * session);
static int feeddriver_feed_error_to_mail_error(int error)
{
switch (error) {
case NEWSFEED_NO_ERROR:
return MAIL_NO_ERROR;
case NEWSFEED_ERROR_CANCELLED:
return MAIL_ERROR_STREAM;
case NEWSFEED_ERROR_INTERNAL:
return MAIL_ERROR_UNKNOWN;
case NEWSFEED_ERROR_BADURL:
return MAIL_ERROR_INVAL;
case NEWSFEED_ERROR_RESOLVE_PROXY:
case NEWSFEED_ERROR_RESOLVE_HOST:
return MAIL_ERROR_CONNECT;
case NEWSFEED_ERROR_CONNECT:
return MAIL_ERROR_CONNECT;
case NEWSFEED_ERROR_STREAM:
return MAIL_ERROR_STREAM;
case NEWSFEED_ERROR_PROTOCOL:
case NEWSFEED_ERROR_PARSE:
return MAIL_ERROR_PARSE;
case NEWSFEED_ERROR_ACCESS:
return MAIL_ERROR_NO_PERMISSION;
case NEWSFEED_ERROR_AUTHENTICATION:
return MAIL_ERROR_LOGIN;
case NEWSFEED_ERROR_FTP:
return MAIL_ERROR_UNKNOWN;
case NEWSFEED_ERROR_PARTIAL_FILE:
case NEWSFEED_ERROR_FETCH:
return MAIL_ERROR_FETCH;
case NEWSFEED_ERROR_HTTP:
return MAIL_ERROR_UNKNOWN;
case NEWSFEED_ERROR_FILE:
return MAIL_ERROR_FILE;
case NEWSFEED_ERROR_PUT:
return MAIL_ERROR_APPEND;
case NEWSFEED_ERROR_MEMORY:
return MAIL_ERROR_MEMORY;
case NEWSFEED_ERROR_SSL:
return MAIL_ERROR_SSL;
case NEWSFEED_ERROR_LDAP:
return MAIL_ERROR_UNKNOWN;
case NEWSFEED_ERROR_UNSUPPORTED_PROTOCOL:
return MAIL_ERROR_INVAL;
}
return MAIL_ERROR_UNKNOWN;
}
static inline struct feed_session_state_data *
get_data(mailsession * session)
{
return session->sess_data;
}
static inline struct newsfeed * get_feed_session(mailsession * session)
{
return get_data(session)->feed_session;
}
static int feeddriver_initialize(mailsession * session)
{
struct feed_session_state_data * data;
struct newsfeed * feed;
feed = newsfeed_new();
if (feed == NULL)
goto err;
data = malloc(sizeof(* data));
if (data == NULL)
goto free;
data->feed_session = feed;
data->feed_error = MAIL_NO_ERROR;
session->sess_data = data;
return MAIL_NO_ERROR;
free:
newsfeed_free(feed);
err:
return MAIL_ERROR_MEMORY;
}
static void feeddriver_uninitialize(mailsession * session)
{
struct feed_session_state_data * data;
data = get_data(session);
newsfeed_free(data->feed_session);
free(data);
session->sess_data = NULL;
}
static int feeddriver_connect_path(mailsession * session, const char * path)
{
struct feed_session_state_data * data;
int r;
data = get_data(session);
r = newsfeed_set_url(data->feed_session, path);
return feeddriver_feed_error_to_mail_error(r);
}
static int feeddriver_status_folder(mailsession * session, const char * mb,
uint32_t * result_messages,
uint32_t * result_recent,
uint32_t * result_unseen)
{
uint32_t count;
int r;
r = feeddriver_messages_number(session, mb, &count);
if (r != MAIL_NO_ERROR)
return r;
* result_messages = count;
* result_recent = count;
* result_unseen = count;
return MAIL_NO_ERROR;
}
static int feeddriver_messages_number(mailsession * session, const char * mb,
uint32_t * result)
{
struct feed_session_state_data * data;
unsigned int count;
int res;
update(session);
data = get_data(session);
if (data->feed_error != MAIL_NO_ERROR) {
res = data->feed_error;
goto err;
}
count = newsfeed_item_list_get_count(data->feed_session);
* result = count;
return MAIL_NO_ERROR;
err:
return res;
}
static void update(mailsession * session)
{
int r;
struct feed_session_state_data * data;
time_t value;
data = get_data(session);
value = time(NULL);
if (data->feed_last_update != (time_t) -1) {
if (value - data->feed_last_update < MIN_DELAY)
return;
}
r = newsfeed_update(data->feed_session, -1);
data->feed_error = feeddriver_feed_error_to_mail_error(r);
if (data->feed_error == MAIL_NO_ERROR) {
value = time(NULL);
data->feed_last_update = value;
}
}
static int
feeddriver_get_envelopes_list(mailsession * session,
struct mailmessage_list * env_list)
{
return MAIL_NO_ERROR;
}
static mailmessage * feed_item_to_message(mailsession * session,
unsigned int num,
struct newsfeed_item * item)
{
struct mailimf_fields * fields;
struct mailimf_date_time * date_time;
time_t time;
struct mailimf_mailbox_list * from;
mailmessage * msg;
char * subject;
const char * subject_const;
char * msg_id;
int r;
const char * author_const;
from = NULL;
author_const = newsfeed_item_get_author(item);
if (author_const != NULL) {
char * author;
char * addr_spec;
struct mailimf_mailbox * mb;
author = strdup(author_const);
if (author == NULL) {
goto err;
}
from = mailimf_mailbox_list_new_empty();
if (from == NULL) {
free(author);
goto err;
}
addr_spec = strdup("invalid@localhost.local");
if (addr_spec == NULL) {
free(author);
goto free_from;
}
/* XXX - encode author with MIME */
mb = mailimf_mailbox_new(author, addr_spec);
if (mb == NULL) {
free(addr_spec);
free(author);
goto free_from;
}
r = mailimf_mailbox_list_add(from, mb);
if (r != MAILIMF_NO_ERROR) {
mailimf_mailbox_free(mb);
goto free_from;
}
}
date_time = NULL;
time = newsfeed_item_get_date_modified(item);
if (time != (time_t) -1) {
date_time = mailimf_get_date(time);
if (date_time == NULL) {
goto free_from;
}
}
subject = NULL;
subject_const = newsfeed_item_get_title(item);
if (subject_const != NULL) {
subject = strdup(subject_const);
if (subject == NULL) {
goto free_date;
}
}
msg_id = mailimf_get_message_id();
if (msg_id == NULL) {
goto free_subject;
}
fields = mailimf_fields_new_with_data_all(date_time,
from,
NULL,
NULL,
NULL,
NULL,
NULL,
msg_id,
NULL,
NULL,
subject);
msg = mailmessage_new();
r = mailmessage_init(msg, session, feed_message_driver, num, 0);
if (r != MAIL_NO_ERROR) {
goto free_fields;
}
msg->msg_fields = fields;
return msg;
free_fields:
mailimf_fields_free(fields);
goto err;
free_subject:
free(subject);
free_date:
mailimf_date_time_free(date_time);
free_from:
mailimf_mailbox_list_free(from);
err:
return NULL;
}
static int feeddriver_get_messages_list(mailsession * session,
struct mailmessage_list ** result)
{
unsigned int i;
struct feed_session_state_data * data;
unsigned int count;
struct mailmessage_list * msg_list;
carray * tab;
int res;
int r;
update(session);
data = get_data(session);
if (data->feed_error != MAIL_NO_ERROR) {
res = data->feed_error;
goto err;
}
count = newsfeed_item_list_get_count(data->feed_session);
tab = carray_new(count);
if (tab == NULL) {
res = MAIL_ERROR_MEMORY;
goto err;
}
fprintf(stderr, "count: %i\n", count);
for(i = 0 ; i < count ; i ++) {
struct newsfeed_item * item;
mailmessage * msg;
item = newsfeed_get_item(data->feed_session, i);
msg = feed_item_to_message(session, i, item);
r = carray_add(tab, msg, NULL);
if (r < 0) {
res = MAIL_ERROR_MEMORY;
goto free_tab;
}
}
msg_list = mailmessage_list_new(tab);
if (msg_list == NULL) {
res = MAIL_ERROR_MEMORY;
goto free_tab;
}
* result = msg_list;
return MAIL_NO_ERROR;
free_tab:
for(i = 0 ; i < carray_count(tab) ; i ++) {
mailmessage * msg;
msg = carray_get(tab, i);
mailmessage_free(msg);
}
err:
return res;
}
static int feeddriver_get_message(mailsession * session,
uint32_t num, mailmessage ** result)
{
mailmessage * msg_info;
int r;
msg_info = mailmessage_new();
if (msg_info == NULL)
return MAIL_ERROR_MEMORY;
r = mailmessage_init(msg_info, session, feed_message_driver, num, 0);
if (r != MAIL_NO_ERROR) {
mailmessage_free(msg_info);
return r;
}
* result = msg_info;
return MAIL_NO_ERROR;
}
static int feeddriver_get_message_by_uid(mailsession * session,
const char * uid,
mailmessage ** result)
{
#if 0
uint32_t num;
char * p;
if (uid == NULL)
return MAIL_ERROR_INVAL;
num = strtoul(uid, &p, 10);
if ((p == uid) || (* p != '\0'))
return MAIL_ERROR_INVAL;
return feeddriver_get_message(session, num, result);
#endif
return MAIL_ERROR_INVAL;
}
syntax highlighted by Code2HTML, v. 0.9.1