/* copyright and license info go here */ #include "unixmbox.h" /* * Opens and locks a mailbox */ int unixmbox_open (mailbox * mbox) { char buf[80]; unsigned int max_count = 10; int mess = 0; unixmbox_data *data = malloc (sizeof (unixmbox_data)); if (data == NULL) { errno = ENOMEM; free (data); return -1; } mbox->_data = data; data->file = fopen (mbox->name, "r+"); /* FIXME: do a good, NFS safe, file lock here, with error handling */ if (data->file == NULL) { /* errno is set by fopen() */ free (data); return -1; } data->messages = malloc (sizeof (unixmbox_message) * max_count); mbox->sizes = malloc (sizeof (int) * max_count); if (data->messages == NULL || mbox->sizes == NULL) { unixmbox_close (mbox); errno = ENOMEM; return -1; } while (fgets (buf, 80, data->file)) { if (!strncmp (buf, "From ", 5)) { /* Beginning of a header */ while (strchr (buf, '\n') == NULL) fgets (buf, 80, data->file); mbox->messages++; if (mbox->messages > max_count) { max_count = mbox->messages * 2; data->messages = realloc (data->messages, max_count * sizeof (unixmbox_message)); mbox->sizes = realloc (mbox->sizes, max_count * sizeof (int)); if (data->messages == NULL || mbox->sizes == NULL) { unixmbox_close (mbox); errno = ENOMEM; return -1; } } fgetpos (data->file, &(data->messages[mbox->messages - 1].header)); mbox->sizes[mbox->messages - 1] = 0; data->messages[mbox->messages - 1].deleted = 0; mess = 0; } else if (((!strncmp (buf, "\r\n", 2) || strlen (buf) <= 1)) && mess == 0) { /* Beginning of a body */ fgetpos (data->file, &(data->messages[mbox->messages - 1].body)); mbox->sizes[mbox->messages - 1] += strlen (buf) + 1; mess = 1; } else { mbox->sizes[mbox->messages - 1] += strlen (buf) + 1; fgetpos (data->file, &(data->messages[mbox->messages - 1].end)); } } mbox->_close = unixmbox_close; mbox->_delete = unixmbox_delete; mbox->_undelete = unixmbox_undelete; mbox->_expunge = unixmbox_expunge; mbox->_add_message = unixmbox_add_message; mbox->_is_deleted = unixmbox_is_deleted; mbox->_get_body = unixmbox_get_body; mbox->_get_header = unixmbox_get_header; return 0; } /* * Closes and unlocks a mailbox, does not expunge */ int unixmbox_close (mailbox * mbox) { unixmbox_data *data = mbox->_data; /* FIXME: good file unlocking, to go along with the locking above */ fclose (data->file); free (data->messages); free (mbox->sizes); free (data); free (mbox); return 0; } /* * Marks a message for deletion */ int unixmbox_delete (mailbox * mbox, int num) { unixmbox_data *data = mbox->_data; if (num > mbox->messages || mbox_is_deleted (mbox, num)) { errno = ERANGE; return -1; } else { data->messages[num].deleted = 1; mbox->num_deleted++; } return 0; } /* * Unmark a message for deletion */ int unixmbox_undelete (mailbox * mbox, int num) { unixmbox_data *data = mbox->_data; if (num > mbox->messages || !mbox_is_deleted (mbox, num)) { errno = ERANGE; return -1; } else { data->messages[num].deleted = 0; mbox->num_deleted--; } return 0; } /* * Updates a mailbox to remove message marked for deletion * FIXME: BROKEN! DOES NOT WORK! BLOWS UP REAL GOOD! */ int unixmbox_expunge (mailbox * mbox) { unixmbox_data *data = mbox->_data; int i = 0, size = 0; char *buf; fpos_t lastpos; data->file = freopen (mbox->name, "r+", data->file); if (data->file == NULL) { /* error handling */ } fgetpos (data->file, &lastpos); for (i = 0; i < mbox->messages; i++) { if (data->messages[i].deleted == 0) { fgetpos (data->file, &lastpos); fsetpos (data->file, &(data->messages[i].header)); read (fileno (data->file), buf, data->messages[i + 1].header - data->messages[i].header); fprintf (data->file, "%s", buf); size += strlen (buf); free (buf); } } ftruncate (fileno (data->file), size); return 0; } /* * Determines whether or a not a message is marked for deletion */ int unixmbox_is_deleted (mailbox * mbox, int num) { unixmbox_data *data = mbox->_data; return (data->messages[num].deleted == 1); } /* * Adds a message to the mailbox */ int unixmbox_add_message (mailbox * mbox, char *message) { /* * FIXME: please write me * move to end of file and write text, don't forget to update * mbox->messages and mbox->_data->messages */ errno = ENOSYS; return -1; } /* * Returns a message body */ char * unixmbox_get_body (mailbox * mbox, int num) { unixmbox_data *data = mbox->_data; int size = data->messages[num].end - data->messages[num].body; char *buf = malloc ((1 + size) * sizeof (char)); if (buf == NULL) { errno = ENOMEM; free (buf); return NULL; } else if (num > mbox->messages || num < 0) { errno = ERANGE; free (buf); return NULL; } memset (buf, 0, size + 1); fsetpos (data->file, &(data->messages[num].body)); fread (buf, size, sizeof (char), data->file); return buf; } /* * Returns just the header of a message */ char * unixmbox_get_header (mailbox * mbox, int num) { unixmbox_data *data = mbox->_data; int size = (data->messages[num].body - 1) - data->messages[num].header ; char *buf = malloc ((1 + size) * sizeof (char)); if (buf == NULL) { errno = ENOMEM; free (buf); return NULL; } else if (num > mbox->messages || num < 0) { errno = ERANGE; free (buf); return NULL; } memset (buf, 0, size + 1); fsetpos (data->file, &(data->messages[num].header)); fread (buf, size, sizeof (char), data->file); return buf; }