#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <iconv.h>
#include<arpa/inet.h>
#define MSGLINE 5000
#define OUTSIZE 1024
/* hexadecimal lookup table */
static char hex[] = "0123456789ABCDEF";
/* URL unsafe printable characters */
static char urlunsafe[] = " \"#%&+:;<=>?@[\\]^`{|}";
/* UTF7 modified base64 alphabet */
static char base64chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
#define UNDEFINED 64
/* UTF16 definitions */
#define UTF16MASK 0x03FFUL
#define UTF16SHIFT 10
#define UTF16BASE 0x10000UL
#define UTF16HIGHSTART 0xD800UL
#define UTF16HIGHEND 0xDBFFUL
#define UTF16LOSTART 0xDC00UL
#define UTF16LOEND 0xDFFFUL
/* Convert an IMAP mailbox to a URL path
* dst needs to have roughly 4 times the storage space of src
* Hex encoding can triple the size of the input
* UTF-7 can be slightly denser than UTF-8
* (worst case: 8 octets UTF-7 becomes 9 octets UTF-8)
*/
void MailboxToURL(char *dst, char *src)
{
unsigned char c, i, bitcount;
unsigned long ucs4, utf16, bitbuf;
unsigned char base64[256], utf8[6];
/* initialize modified base64 decoding table */
memset(base64, UNDEFINED, sizeof (base64));
for (i = 0; i < sizeof (base64chars); ++i) {
base64[base64chars[i]] = i;
}
/* loop until end of string */
while (*src != '\0') {
c = *src++;
/* deal with literal characters and &- */
if (c != '&' || *src == '-') {
if (c < ' ' || c > '~' || strchr(urlunsafe, c) != NULL) {
/* hex encode if necessary */
dst[0] = '%';
dst[1] = hex[c >> 4];
dst[2] = hex[c & 0x0f];
dst += 3;
} else {
/* encode literally */
*dst++ = c;
}
/* skip over the '-' if this is an &- sequence */
if (c == '&') ++src;
} else {
/* convert modified UTF-7 -> UTF-16 -> UCS-4 -> UTF-8 -> HEX */
bitbuf = 0;
bitcount = 0;
ucs4 = 0;
while ((c = base64[(unsigned char) *src]) != UNDEFINED) {
++src;
bitbuf = (bitbuf << 6) | c;
bitcount += 6;
/* enough bits for a UTF-16 character? */
if (bitcount >= 16) {
bitcount -= 16;
utf16 = (bitcount ? bitbuf >> bitcount
: bitbuf) & 0xffff;
/* convert UTF16 to UCS4 */
if
(utf16 >= UTF16HIGHSTART && utf16 <= UTF16HIGHEND) {
ucs4 = (utf16 - UTF16HIGHSTART) << UTF16SHIFT;
continue;
} else if
(utf16 >= UTF16LOSTART && utf16 <= UTF16LOEND) {
ucs4 += utf16 - UTF16LOSTART + UTF16BASE;
} else {
ucs4 = utf16;
}
/* convert UTF-16 range of UCS4 to UTF-8 */
if (ucs4 <= 0x7fUL) {
utf8[0] = ucs4;
i = 1;
} else if (ucs4 <= 0x7ffUL) {
utf8[0] = 0xc0 | (ucs4 >> 6);
utf8[1] = 0x80 | (ucs4 & 0x3f);
i = 2;
} else if (ucs4 <= 0xffffUL) {
utf8[0] = 0xe0 | (ucs4 >> 12);
utf8[1] = 0x80 | ((ucs4 >> 6) & 0x3f);
utf8[2] = 0x80 | (ucs4 & 0x3f);
i = 3;
} else {
utf8[0] = 0xf0 | (ucs4 >> 18);
utf8[1] = 0x80 | ((ucs4 >> 12) & 0x3f);
utf8[2] = 0x80 | ((ucs4 >> 6) & 0x3f);
utf8[3] = 0x80 | (ucs4 & 0x3f);
i = 4;
}
/* convert utf8 to hex */
for (c = 0; c < i; ++c) {
dst[0] = '%';
dst[1] = hex[utf8[c] >> 4];
dst[2] = hex[utf8[c] & 0x0f];
dst += 3;
}
}
}
/* skip over trailing '-' in modified UTF-7 encoding */
if (*src == '-') ++src;
}
}
/* terminate destination string */
*dst = '\0';
}
/* Convert hex coded UTF-8 URL path to modified UTF-7 IMAP mailbox
* dst should be about twice the length of src to deal with non-hex
* coded URLs
*/
void URLtoMailbox(char *dst, char *src)
{
unsigned int utf8pos, utf8total, i, c, utf7mode, bitstogo, utf16flag;
unsigned long ucs4, bitbuf;
unsigned char hextab[256];
/* initialize hex lookup table */
memset(hextab, 0, sizeof (hextab));
for (i = 0; i < sizeof (hex); ++i) {
hextab[hex[i]] = i;
if (isupper(hex[i])) hextab[tolower(hex[i])] = i;
}
utf7mode = 0;
utf8total = 0;
bitstogo = 0;
while ((c = *src) != '\0') {
++src;
/* undo hex-encoding */
if (c == '%' && src[0] != '\0' && src[1] != '\0') {
c = (hextab[src[0]] << 4) | hextab[src[1]];
src += 2;
}
/* normal character? */
if (c >= ' ' && c <= '~') {
/* switch out of UTF-7 mode */
if (utf7mode) {
if (bitstogo) {
*dst++ = base64chars[(bitbuf << (6 - bitstogo)) & 0x3F];
}
*dst++ = '-';
utf7mode = 0;
}
*dst++ = c;
/* encode '&' as '&-' */
if (c == '&') {
*dst++ = '-';
}
continue;
}
/* switch to UTF-7 mode */
if (!utf7mode) {
*dst++ = '&';
utf7mode = 1;
}
/* Encode US-ASCII characters as themselves */
if (c < 0x80) {
ucs4 = c;
utf8total = 1;
} else if (utf8total) {
/* save UTF8 bits into UCS4 */
ucs4 = (ucs4 << 6) | (c & 0x3FUL);
if (++utf8pos < utf8total) {
continue;
}
} else {
utf8pos = 1;
if (c < 0xE0) {
utf8total = 2;
ucs4 = c & 0x1F;
} else if (c < 0xF0) {
utf8total = 3;
ucs4 = c & 0x0F;
} else {
/* NOTE: can't convert UTF8 sequences longer than 4 */
utf8total = 4;
ucs4 = c & 0x03;
}
continue;
}
/* loop to split ucs4 into two utf16 chars if necessary */
utf8total = 0;
do {
if (ucs4 >= UTF16BASE) {
ucs4 -= UTF16BASE;
bitbuf = (bitbuf << 16) | ((ucs4 >> UTF16SHIFT)
+ UTF16HIGHSTART);
ucs4 = (ucs4 & UTF16MASK) + UTF16LOSTART;
utf16flag = 1;
} else {
bitbuf = (bitbuf << 16) | ucs4;
utf16flag = 0;
}
bitstogo += 16;
/* spew out base64 */
while (bitstogo >= 6) {
bitstogo -= 6;
*dst++ = base64chars[(bitstogo ? (bitbuf >> bitstogo)
: bitbuf)
& 0x3F];
}
} while (utf16flag);
}
/* if in UTF-7 mode, finish in ASCII */
if (utf7mode) {
if (bitstogo) {
*dst++ = base64chars[(bitbuf << (6 - bitstogo)) & 0x3F];
}
*dst++ = '-';
}
/* tie off string */
*dst = '\0';
}
int main(int argc, char **argv)
{
if(argc < 5)
{
printf("usage: %s maildir serverip serverport passwd\n", argv[0]);
exit(1);
}
/* open data directoty */
DIR *dirp = opendir(argv[1]);
if(!dirp)
{
printf("cannot access %s\n", argv[1]);
exit(1);
}
char request[MSGLINE];
char response[MSGLINE];
struct dirent *dent;
/* get user mail accounts */
while((dent = readdir(dirp)))
{
if(dent->d_type != DT_DIR || *dent->d_name == '.')
continue;
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_fd < 0)
{
printf("create socket failed\n");
exit(1);
}
struct sockaddr_in srvaddr;
memset(&srvaddr,0,sizeof(srvaddr));
AF_ srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.s_addr = inet_addr(argv[2]);
srvaddr.sin_port = htons(atoi(argv[3]));
if(connect(socket_fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr)) < 0)
{
printf("connect to server failed\n");
exit(1);
}
printf("USER: %s\n", dent->d_name);
read(socket_fd, response, MSGLINE);
sprintf(request, "lll login %s %s\r\n", dent->d_name, argv[4]);
write(socket_fd, request, strlen(request));
read(socket_fd, response, MSGLINE);
if(strncmp(response, "lll ", 4) || strncmp(response+4, "OK", 2))
{
printf("%s login failed\n", dent->d_name);
write(socket_fd, "ttt logout\r\n", strlen("ttt logout\r\n"));
read(socket_fd, response, MSGLINE);
close(socket_fd);
continue;
// exit(1);
}
char userfname[1024];
sprintf(userfname, "%s/%s", argv[1], dent->d_name);
DIR *userp = opendir(userfname);
if(!userp)
{
printf("cannot access %s\n", userfname);
exit(1);
}
struct dirent *userdent;
/* get user's mailbox names */
while((userdent = readdir(userp)))
{
if(userdent->d_type != DT_DIR || *userdent->d_name == '.')
continue;
if(strcmp(userdent->d_name, "Delbox") == 0)
continue;
char boxfname[1024];
sprintf(boxfname, "%s/%s", userfname, userdent->d_name);
DIR *boxp = opendir(boxfname);
if(!boxp)
{
printf("cannot access %s\n", boxfname);
exit(1);
}
char boxname[OUTSIZE];
memset(boxname, 0, OUTSIZE);
char midtrans[OUTSIZE];
strcpy(boxname, userdent->d_name);
MailboxToURL(midtrans,boxname);
URLtoMailbox(boxname,midtrans);
struct dirent *boxdent;
/* get mails in the mailbox */
while((boxdent = readdir(boxp)))
{
if(boxdent->d_type != DT_REG)
continue;
char mailfname[1024];
sprintf(mailfname, "%s/%s", boxfname, boxdent->d_name);
int fd = open(mailfname, O_RDONLY);
if(fd == -1)
{
printf("open %s failed\n", mailfname);
exit(1);
}
int len = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
/* compose append command and send to server */
sprintf(request, "aaa append %s (\\Seen) {%d}\r\n", boxname, len-2);
write(socket_fd, request, strlen(request));
int sz = read(socket_fd, response, MSGLINE);
response[sz] = 0;
if(strncmp(response,"aaa NO [TRYCREATE]", strlen("aaa NO [TRYCREATE]")) == 0)
{
sprintf(request, "ccc create %s\r\n", boxname);
write(socket_fd, request, strlen(request));
int sz = read(socket_fd, response, MSGLINE);
response[sz] = 0;
if(strncmp(response, "ccc OK", strlen("ccc OK")) == 0)
{
sprintf(request, "aaa append %s (\\Seen) {%d}\r\n", boxname, len-2);
write(socket_fd, request, strlen(request));
int sz = read(socket_fd, response, MSGLINE);
response[sz] = 0;
}
else
{
printf("create mailbox %s failed\n", userdent->d_name);
exit(1);
}
}
if(response[0] != '+')
{
printf("submit %s failed, append cmd, error: %s\n", mailfname, response);
exit(1);
}
while(1)
{
int num = read(fd, request, MSGLINE);
if(num < 0)
{
printf("read %s failed\n", mailfname);
exit(1);
}
if(num == 0) break;
int pos = 0;
while(num > 0)
{
int sz = write(socket_fd, request+pos, num);
if(sz < 0)
{
printf("write to socket failed\n");
exit(1);
}
pos += sz;
num -= sz;
}
// write(socket_fd, message, num);
}
close(fd);
sz = read(socket_fd, response, MSGLINE);
response[sz] = 0;
// printf("response: %s\n", message);
if(strncmp(response, "aaa OK", strlen("aaa OK")) == 0)
unlink(mailfname);
else
{
printf("submit %s failed, trans data, error: %s\n", mailfname, response);
exit(1);
}
}
closedir(boxp);
sleep(1);
}
closedir(userp);
write(socket_fd, "ttt logout\r\n", strlen("ttt logout\r\n"));
read(socket_fd, response, MSGLINE);
close(socket_fd);
}
closedir(dirp);
}