Hi all,
I've written a Cyrus->DBMail conversion tool and it takes care of everything
and all messsages come up properly (except for some, with two consequtive @s
in the sender address). In Outlook Express though, all dates show as being
the time that the conversion was performed - not the actual date. KMail and
Mozilla Mail are fine though.
Any suggestions are greatly apprecaited!
Chris
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include "dbmail.h"
#include "db.h"
#include "auth.h"
#include "list.h"
#define MAX_LINE_SIZE 1024
#define UID_SIZE 70
typedef struct stack_node * SNode;
struct stack_node {
char * entry_name;
SNode next;
};
static SNode stack_pointer = NULL;
char * config_file = DEFAULT_CONFIG_FILE;
extern field_t _db_host;
extern field_t _db_db;
extern field_t _db_user;
extern field_t _db_pass;
static u64_t userid;
static char message_buffer[READ_BLOCK_SIZE + MAX_LINE_SIZE + 1];
static char line_buffer[MAX_LINE_SIZE + 1];
static int num_folders = 0;
static int num_messages = 0;
int process_dir(char *, char *);
/* push() : Takes a string and copies it into a SNode. NOTE: Does not store reference to argument.
* Caller may free argument string once push() returns */
void push(char *);
char * pop(void);
int stack_empty(void);
SNode new_SNode(void);
void print_stack(void);
int insert_message(char *, char *);
/* get_curr_dir() : For portability reasons, this function may need modification. Makes use of
* getcwd(). */
char * get_curr_dir(void);
int stack_empty(void) {
return stack_pointer == NULL;
}
SNode new_SNode(void) {
SNode node = (SNode) malloc(sizeof(struct stack_node));
if (node == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
return node;
}
void push(char * entry_name) {
SNode node = new_SNode();
node->next = stack_pointer;
stack_pointer = node;
node->entry_name = (char *) malloc(sizeof(char) * (strlen(entry_name) + 1));
(void) strcpy(node->entry_name, entry_name);
return;
}
char * pop(void) {
char * return_value;
SNode temp;
if (stack_pointer == NULL)
return NULL;
temp = stack_pointer->next;
return_value = stack_pointer->entry_name;
free(stack_pointer);
stack_pointer = temp;
return return_value;
}
void print_stack(void) {
while (!stack_empty())
printf("Stack entry: %s .\n", pop());
return;
}
int process_dir(char * dir, char * base) {
struct stat file;
struct dirent ** filelisting;
int i = 0, n = 0, return_value = 0;
char * entry_name;
char * creation_dir;
u64_t mailbox_id;
int msg_per_folder = 0;
num_folders++;
creation_dir = (1 + dir + strlen(base));
mailbox_id = db_findmailbox(creation_dir, userid);
if (mailbox_id == 0) {
db_createmailbox(creation_dir, userid);
printf("Creating mailbox %s\n", creation_dir);
} else
printf("Mailbox %s already exists.\n", creation_dir);
n = scandir(dir, &filelisting, 0, alphasort);
for (i = 0; i < n; i++) {
if (strcmp(".", filelisting[i]->d_name) == 0) {
free(filelisting[i]);
continue;
}
if (strcmp("..", filelisting[i]->d_name) == 0) {
free(filelisting[i]);
continue;
}
entry_name = (char *) malloc(sizeof(char) * (strlen(dir) + strlen(filelisting[i]->d_name) + 2));
(void) strcpy(entry_name, dir);
(void) strcat(entry_name, "/");
(void) strcat(entry_name, filelisting[i]->d_name);
free(filelisting[i]);
return_value = stat(entry_name, &file);
if (return_value != 0) {
perror("stat");
continue;
}
if (S_ISDIR(file.st_mode)) {
push(entry_name);
continue;
}
if (S_ISREG(file.st_mode)) {
if (strstr(entry_name, "cyrus") != NULL)
continue;
if (strcmp(dir, base) == 0)
creation_dir = "INBOX";
insert_message(creation_dir, entry_name);
msg_per_folder++;
}
}
free(filelisting);
printf("%d messages converted for folder %s\n", msg_per_folder, creation_dir);
num_messages += msg_per_folder;
return 0;
}
char * get_curr_dir(void) {
int size = 32;
char * path = (char *) malloc(sizeof(char) * size);
char * return_value;
if (path == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
return_value = getcwd(path, size);
while (return_value == NULL) {
free(path);
size *= 2;
path = malloc(sizeof(char) * size);
return_value = getcwd(path, size);
}
return path;
}
int main(int argc, char **argv) {
int i;
struct list system_items;
char * dir_name = get_curr_dir();
if (argc != 2) {
fprintf(stderr, "Usage: %s <dbmail username>\n", argv[0]);
fprintf(stderr, "DBMail users must already exist!\n");
exit(EXIT_FAILURE);
}
ReadConfig("DBMAIL", config_file, &system_items);
SetTraceLevel(&system_items);
GetDBParams(_db_host, _db_db, _db_user, _db_pass, &system_items);
if (db_connect() != 0) {
fprintf(stderr, "We're all doomed!");
exit(EXIT_FAILURE);
}
userid = auth_user_exists(argv[1]);
if (userid == 0) {
fprintf(stderr, "Aiiieeee! Non-existant user specified!\n");
exit(EXIT_FAILURE);
}
printf("User id of user %s is %llu.\n", argv[1], userid);
i = process_dir(dir_name, dir_name);
while (!stack_empty())
process_dir(pop(), dir_name);
return 0;
}
int insert_message(char * folder, char * filename) {
FILE * message;
u64_t message_id;
u64_t message_size = 0, newlines = 0;
char unique_id[UID_SIZE];
int buffer_marker = 0;
int line_length = 0;
int single_char_line = 0;
message = fopen(filename, "r");
if (message == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
message_id = db_insert_message(userid, folder, 0);
/* First take care of the header */
snprintf(unique_id, UID_SIZE, "%lluA%lu", userid, time(NULL));
while (single_char_line != 1) {
(void) fgets(line_buffer, MAX_LINE_SIZE, message);
newlines += 1;
line_length = strlen(line_buffer);
line_buffer[line_length - 1] = '\0';
line_buffer[line_length - 2] = '\n';
line_length -= 1;
if (line_length == 1)
single_char_line = 1;
strcpy(&message_buffer[buffer_marker], line_buffer);
buffer_marker += line_length;
message_size += line_length;
}
message_buffer[buffer_marker + 1] = '\0';
db_insert_message_block(message_buffer, message_size, message_id);
db_update_message(message_id, unique_id, message_size, message_size + newlines);
buffer_marker = 0;
while (!feof(message)) {
(void) fgets(line_buffer, MAX_LINE_SIZE, message);
newlines += 1;
line_length = strlen(line_buffer);
line_buffer[line_length - 1] = '\0';
line_buffer[line_length - 2] = '\n';
line_length -= 1;
if (buffer_marker < (READ_BLOCK_SIZE - line_length)) {
(void) strcpy(&message_buffer[buffer_marker], line_buffer);
buffer_marker += line_length;
message_size += line_length;
} else {
db_insert_message_block(message_buffer, buffer_marker, message_id);
buffer_marker = 0;
(void) strcpy(&message_buffer[buffer_marker], line_buffer);
buffer_marker +=line_length;
}
}
db_insert_message_block(message_buffer, buffer_marker, message_id);
db_update_message(message_id, unique_id, message_size, message_size + newlines);
fclose(message);
return 0;
}