dslinux/user/pixil/apps/fltk/mail/lib Makefile cache.c cache.h encoding.c encoding.h mail_pop3.c mail_smtp.c mail_smtp.h mime.c mime.h net_util.c net_util.h nxmail.c nxmail.h rfc822.c rfc822.h str_util.c str_util.h

amadeus dslinux_amadeus at user.in-berlin.de
Tue Oct 3 13:24:24 CEST 2006


Update of /cvsroot/dslinux/dslinux/user/pixil/apps/fltk/mail/lib
In directory antilope:/tmp/cvs-serv11916/apps/fltk/mail/lib

Added Files:
	Makefile cache.c cache.h encoding.c encoding.h mail_pop3.c 
	mail_smtp.c mail_smtp.h mime.c mime.h net_util.c net_util.h 
	nxmail.c nxmail.h rfc822.c rfc822.h str_util.c str_util.h 
Log Message:
adding pristine copy of pixil to HEAD so I can branch from it

--- NEW FILE: encoding.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


static char alphabet[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789+/";


static int
cvt_ascii(unsigned char alpha)
{
    if ((alpha >= 'A') && (alpha <= 'Z'))
	return (int) (alpha - 'A');
    else if ((alpha >= 'a') && (alpha <= 'z'))
	return 26 + (int) (alpha - 'a');
    else if ((alpha >= '0') && (alpha <= '9'))
	return 52 + (int) (alpha - '0');
    else if (alpha == '+')
	return 62;
    else if (alpha == '/')
	return 63;
    else if (alpha == '=')
	return -2;
    else
	return -1;
}

int
decode_base64(unsigned char *in, unsigned char *out, int insize)
{
    int index;

    unsigned char outval;

    unsigned char *outpointer = out;

    int shift = 0;
    unsigned long accum = 0;
    unsigned long value = 0;

    for (index = 0; index < insize; index++) {
	value = cvt_ascii(in[index]);

	if (value < 64) {
	    accum <<= 6;
	    shift += 6;
	    accum |= value;

	    if (shift >= 8) {
		shift -= 8;
		value = accum >> shift;
		outval = (unsigned char) value & 0xFFl;
		*outpointer++ = outval;
	    }
	}

    }

    return ((int) (outpointer - out));
}

int
encode_base64(unsigned char *in, unsigned char *out, int insize)
{
    int index;
    unsigned char *outpointer = out;

    unsigned char outval;
    int shift = 0;
    unsigned long accum = 0;
    unsigned long value = 0;

    for (index = 0; index < insize; index++) {
	value = (unsigned long) in[index];

	accum <<= 8;
	shift += 8;
	accum |= value;

	while (shift >= 6) {
	    shift -= 6;
	    value = (accum >> shift) & 0x3Fl;
	    outval = alphabet[value];

	    *outpointer++ = outval;
	}
    }

    return ((int) (outpointer - out));
}

--- NEW FILE: mail_smtp.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#include "nxmail.h"
#include "net_util.h"
#include "mail_smtp.h"

#define OK      0
#define FAILURE 1
#define ERROR   2

static char *SMTPProtoArray[] = { NULL, "HELO %s\n", "MAIL FROM:<%s>\n",
    "RCPT TO:<%s>\n", "DATA\n", "\n.\n", "QUIT\n"
};

static int smtp_handle_response(SMTPCommands state, int response);

static int
smtp_send_command(int fd, char *command, int len)
{
#ifdef DEBUG
    printf("SMTP:  Sending <%s> <%d>\n", command, len);
#endif

    if (tcp_wait_for_socket(fd, 5, TCP_WRITE) <= 0)
	return (-1);

    return (write(fd, command, len));
}

static int
smtp_get_response(int fd, char *response, int len)
{
    int lindex;
    int ret;

    if (tcp_wait_for_socket(fd, 5, TCP_READ) <= 0)
	return (-1);

    bzero(response, len);

    ret = fdgets(fd, response, len - 1);

    if (ret <= 0)
	return (-1);

    /* Strip the CRLF and just turn it into a CR */
    lindex = (strlen(response) - 1);

    if (response[lindex] == '\n' && response[lindex - 1] == '\r') {
	response[lindex - 1] = '\n';
	response[lindex] = 0;
    }
#ifdef DEBUG
    printf("SMTP:  Got <%s>", response);
#endif

    return (0);
}

static int
smtp_command(int fd, SMTPCommands cmd, char *data)
{
    char cmdstr[1024];
    char response[1024];

    if (SMTPProtoArray[cmd]) {
	bzero(cmdstr, 1024);

	if (data)
	    sprintf(cmdstr, SMTPProtoArray[cmd], data);
	else
	    strcpy(cmdstr, SMTPProtoArray[cmd]);

	if (smtp_send_command(fd, cmdstr, strlen(cmdstr)) == -1)
	    return (SMTP_NET_ERROR);
    }

    do {
	if (smtp_get_response(fd, response, 1024) == -1)
	    return (SMTP_NET_ERROR);
    }

    while (atoi(response) == 0);

    return (atoi(response));
}

static int
smtp_send_data(int fd, char *buffer, int bufferlen)
{
    int len;
    int outlen = 0;

    while (1) {
#ifdef DEBUG
	printf("SMTP:  Sending %s\n", buffer + outlen);
#endif

	if (tcp_wait_for_socket(fd, 5, TCP_WRITE) <= 0)
	    return (-1);

	len = write(fd, buffer + outlen, bufferlen - outlen);

	if (len <= 0) {
	    perror("SMTP_SEND_DATA (WRITE)\n");
	    return (-1);
	}

	if (len == (bufferlen - outlen))
	    break;
	outlen += len;
    }

    return (0);
}

int
smtp_send_message(char *server, int port, nxmail_header_t * header,
		  char *body, int bodylen)
{
    SMTPCommands state = 0;
    int addrok = 0;

    nxmail_address_t *tolist = &header->to;

    char *hostname;
    char str[100];
    int ret;

    int fd = tcp_open_stream(server, port);

    if (fd == -1)
	return (NXMAIL_SEND_ERROR);

    printf("SEND:  Opened up %d for socket\n", fd);

    hostname = tcp_get_hostname(fd);

    if (!hostname) {
	printf("SMTP:  Couldn't resolve the local host\n");
	close(fd);
	return (NXMAIL_SEND_ERROR);
    }

    state = SMTP_LOGON;
    ret = smtp_command(fd, state, 0);
    if (smtp_handle_response(state, ret) != OK)
	goto end_session;

    /* Send HELLO */
    state = SMTP_HELLO;

    ret = smtp_command(fd, state, hostname);
    if (smtp_handle_response(state, ret) != OK)
	goto end_session;

    /* Send MAIL FROM */
    state = SMTP_MAIL;

    sprintf(str, "%s@%s", header->from.mailbox, header->from.host);
    ret = smtp_command(fd, state, str);
    if (smtp_handle_response(state, ret) != OK)
	goto end_session;

    /* Send RECT TO: for all names on the list */
    state = SMTP_RECPT;

    while (tolist) {
	sprintf(str, "%s@%s", tolist->mailbox, tolist->host);
	ret = smtp_command(fd, state, str);

	switch (smtp_handle_response(state, ret)) {
	case ERROR:
	    goto end_session;
	case OK:
	    addrok++;
	}

	tolist->result = ret;
	tolist = tolist->next;
    }

    if (!addrok) {
	ret = SMTP_NO_MAILBOX;
	goto end_session;
    }

    /* Send DATA */
    state = SMTP_DATA;
    ret = smtp_command(fd, state, 0);
    if (smtp_handle_response(state, ret) != OK)
	goto end_session;

    smtp_send_data(fd, body, bodylen);

    state = SMTP_DATA_END;
    ret = smtp_command(fd, state, 0);

  end_session:

    printf("SEND: Sending quit!\n");

    smtp_command(fd, SMTP_QUIT, 0);
    close(fd);

    switch (smtp_handle_response(state, ret)) {
    case OK:
	return (NXMAIL_SEND_OK);
    case FAILURE:
	return (NXMAIL_SEND_FAILURE);
    default:
	return (NXMAIL_SEND_ERROR);
    }
}

/* This returns a OK, FAILURE, or ERROR depending on the result */

static int
smtp_handle_response(SMTPCommands state, int response)
{
    switch (state) {
    case SMTP_LOGON:
	if (response != SMTP_READY)
	    return FAILURE;
	return OK;

    case SMTP_HELLO:
	if (response != SMTP_OK)
	    return ERROR;
	return OK;

    case SMTP_MAIL:
	switch (response) {
	case SMTP_OK:
	    return (OK);
	case SMTP_MAILBOX_FULL:
	case SMTP_LOCAL_ERROR:
	case SMTP_SYSTEM_FULL:
	    return (FAILURE);
	default:
	    return (ERROR);
	}

    case SMTP_RECPT:
	switch (response) {
	case SMTP_OK:
	case SMTP_FORWARDED:
	    return (OK);
	case SMTP_SYNTAX_ERROR:
	case SMTP_BAD_ARGUMENT:
	case SMTP_BAD_SEQUENCE:
	case SMTP_NO_SERVICE:
	    return (ERROR);
	default:
	    return (FAILURE);
	}

    case SMTP_DATA:
	if (response != SMTP_READY_FOR_DATA)
	    return (ERROR);
	return (OK);

    case SMTP_DATA_END:
	if (response == SMTP_OK)
	    return (OK);
	return (ERROR);

    default:
	return (FAILURE);
    }
}

--- NEW FILE: net_util.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include "net_util.h"

int nxmail_neterror = 0;

int
tcp_wait_for_socket(int fd, int len, int action)
{
    int ret;
    fd_set fdset;
    struct timeval timeval;

    FD_ZERO(&fdset);
    FD_SET(fd, &fdset);

    timeval.tv_sec = len;
    timeval.tv_usec = 0;

    if (action == TCP_READ)
	ret = select(fd + 1, &fdset, 0, 0, &timeval);
    else
	ret = select(fd + 1, 0, &fdset, 0, &timeval);

    if (ret == -1)
	perror("TCP_WAIT_FOR_SOCKET (SELECT)");
    return (ret);
}

int
tcp_open_stream(char *address, int port)
{
    int ret;
    int fd;
    int serror;
    int slen = sizeof(serror);

    struct sockaddr_in outsock;
    struct hostent *host = gethostbyname(address);
    struct in_addr *hostaddr;

    if (!host)
	return (-1);
    hostaddr = (struct in_addr *) host->h_addr_list[0];

    fd = socket(PF_INET, SOCK_STREAM, 0);

    if (fd == -1) {
	perror("TCP_OPEN_STREAM (SOCKET)");
	SET_NET_ERROR(errno);
	return (-1);
    }

    /* Set it non blocking */
    if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
	perror("TCP_OPEN_sTREAM (FCNTL)");
	SET_NET_ERROR(errno);
	close(fd);
	return (-1);
    }

    outsock.sin_family = AF_INET;
    outsock.sin_port = htons(port);
    outsock.sin_addr.s_addr = hostaddr->s_addr;

    /* A small change here.  A call to connect immediately */
    /* returns a EINPROGRESS, and then we wait for further events */
    /* to come in via poll or select */

    ret =
	connect(fd, (struct sockaddr *) &outsock, sizeof(struct sockaddr_in));

    if (ret == 0)
	return (fd);

    if (errno != EINPROGRESS) {
	perror("TCP_OPEN_STREAM (CONNECT)");
	SET_NET_ERROR(errno);
	close(fd);
	return (-1);
    }

    ret = tcp_wait_for_socket(fd, 5, TCP_WRITE);

    if (ret == -1) {
	SET_NET_ERROR(errno);
	close(fd);
	return (-1);
    }

    if (ret == 0) {
	printf("TCP_OPEN_STREAM - TIMEOUT ON CONNECT\n");
	close(fd);
	return (-1);
    }

    /* No error or timeout, check to see if there was an error */
    getsockopt(fd, SOL_SOCKET, SO_ERROR, &serror, &slen);

    if (serror != 0) {
	printf("TCP_OPEN_STREAM:  %d\n", serror);
	SET_NET_ERROR(serror);
	close(fd);
	return (-1);
    }

    return (fd);
}

char *
tcp_get_hostname(int fd)
{
    struct sockaddr_in saddr;
    struct hostent *host;
    unsigned long addr;

    int slen = sizeof(struct sockaddr_in);

    if (getsockname(fd, (struct sockaddr *) &saddr, &slen) == -1) {
	perror("TCP_GET_HOSTNAME (GETSOCKNAME)");
	SET_NET_ERROR(errno);
	return (0);
    }

    addr = saddr.sin_addr.s_addr;

    host = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);

    if (!host) {
	return (0);
    }

    return (host->h_name);
}

/* Read up to len or until we are out of data, which */
/* ever comes first */

int
fdgets(int fd, char *buffer, int len)
{
    int outsize = 0;

    char *ptr = buffer;

    while (1) {
	int res = read(fd, ptr, 1);

	if (res <= 0) {
	    if (res == -1 && errno != EAGAIN) {
		perror("FDGETS (READ)");
		return (-1);
	    }

	    *ptr = 0;
	    return (outsize);
	}

	if (*ptr == '\n') {
	    if (outsize + 1 < len)
		*(ptr + 1) = 0;
	    return (outsize);
	}

	ptr++;
	if (outsize++ == len)
	    return (len);
    }
}

--- NEW FILE: rfc822.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef RFC822_H
#define RFC822_H

void rfc822_parse_date(char *date, nxmail_date_t * out);
void rfc822_parse_address(nxmail_address_t * out, char *addr);
int rfc822_parse_body(char *buffer, char *body);
void rfc822_parse_header(char *buffer, nxmail_header_t * header, int size);

int rfc822_build_message(nxmail_header_t *, char *, char *);
char *rfc822_getline(char *in, char *out, int size);

#endif

--- NEW FILE: net_util.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef UTIL_H
#define UTIL_H

#define TCP_WRITE 0
#define TCP_READ  1

extern int nxmail_neterror;
extern int errno;

#define SET_NET_ERROR(value) (nxmail_neterror = value)
#define GET_NET_ERROR        (nxmail_neterror)

int tcp_open_stream(char *address, int port);
char *tcp_get_hostname(int fd);
int tcp_wait_for_socket(int fd, int len, int action);

int fdgets(int fd, char *buf, int len);

#endif

--- NEW FILE: mail_smtp.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef MAIL_SMTP_H
#define MAIL_SMTP_H

typedef enum
{
    SMTP_LOGON = 0,
    SMTP_HELLO,
    SMTP_MAIL,
    SMTP_RECPT,
    SMTP_DATA,
    SMTP_DATA_END,
    SMTP_QUIT
}
SMTPCommands;

/* SMTP ERROR MESSAGES */

#define SMTP_NET_ERROR        1
#define SMTP_READY            220
#define SMTP_CLOSED           221
#define SMTP_OK               250
#define SMTP_FORWARDED        251
#define SMTP_READY_FOR_DATA   354
#define SMTP_NO_SERVICE       421
#define SMTP_MAILBOX_UNAVAIL  450
#define SMTP_LOCAL_ERROR      451
#define SMTP_SYSTEM_FULL      452
#define SMTP_SYNTAX_ERROR     500
#define SMTP_BAD_ARGUMENT     501
#define SMTP_NO_COMMAND       502
#define SMTP_BAD_SEQUENCE     503
#define SMTP_PARAM_NOT_AVAIL  504
#define SMTP_NO_MAILBOX       550
#define SMTP_USR_NOT_LOCAL    551
#define SMTP_MAILBOX_FULL     552
#define SMTP_BAD_MAILBOX_NAME 553
#define SMTP_FAILURE          554

int smtp_send_message(char *, int, nxmail_header_t *, char *, int);
#endif

--- NEW FILE: encoding.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef ENCODING_H
#define ENCODING_H

int encode_base64(unsigned char *in, unsigned char *out, int insize);
int decode_base64(unsigned char *in, unsigned char *out, int insize);

#endif

--- NEW FILE: rfc822.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "nxmail.h"
#include "str_util.h"

/* RFC822 keyword callbacks */

void rfc822_ignore(char *, nxmail_header_t *);
void rfc822_date(char *, nxmail_header_t *);
void rfc822_from(char *, nxmail_header_t *);
void rfc822_to(char *, nxmail_header_t *);
void rfc822_subject(char *, nxmail_header_t *);
void rfc822_cc(char *, nxmail_header_t *);
void rfc822_replyto(char *, nxmail_header_t *);
void rfc822_build_address(nxmail_address_t * out, char *output);

struct
{
    char keyword[20];
    void (*callback) (char *, nxmail_header_t *);
}
rfc822_keywords[] =
{
    /* RFC822 Keywords */

    {
    "return-path", rfc822_ignore}
    , {
    "received", rfc822_ignore}
    , {
    "date", rfc822_date}
    , {
    "resent-date", rfc822_date}
    , {
    "from", rfc822_from}
    , {
    "sender", rfc822_from}
    , {
    "resent-from", rfc822_from}
    , {
    "resent-sender", rfc822_from}
    , {
    "to", rfc822_to}
    , {
    "Resent-to", rfc822_to}
    , {
    "cc", rfc822_cc}
    , {
    "Resent-cc", rfc822_cc}
    , {
    "bcc", rfc822_cc}
    , {
    "resent-bcc", rfc822_cc}
    , {
    "reply-to", rfc822_replyto}
    , {
    "reset-reply-to", rfc822_replyto}
    , {
    "subject", rfc822_subject}
    , {
    "message-id", rfc822_ignore}
    , {
    "resent-message-id", rfc822_ignore}
    , {
    "in-reply-to", rfc822_ignore}
    , {
    "references", rfc822_ignore}
    , {
    "keywords", rfc822_ignore}
    , {
    "comments", rfc822_ignore}
    , {
    "encrypted", rfc822_ignore}
    ,
	/* Extensions to RFC822 */
    {
    "auto-submitted", rfc822_ignore}
    , {
    "user-agent", rfc822_ignore}
    , {
    "status", rfc822_ignore}
    , {
    "<none>", 0}
};

void
rfc822_parse_header(char *buffer, nxmail_header_t * header, int totalsize)
{
    char linebuf[1024];
    char *curptr = buffer;

    /* Parse the header as it was given to us */

    while (curptr) {
	char *nextptr;
	char *keyword, *value;
	int keycount = 0;

	/* Grab the line and strip the endline */
	nextptr = str_getline(curptr, linebuf, 1024);

	/* If the size of the line is zero, then */
	/* start processing the body             */

	if (!strlen(linebuf))
	    break;
	curptr = nextptr;

	/* Go through and parse the keywords */

	if (!str_parsefield(linebuf, ':', &keyword, &value))
	    continue;
	str_lcase(keyword, strlen(keyword));

	keycount = 0;

	while (rfc822_keywords[keycount].callback) {
	    if (!strncmp(keyword, rfc822_keywords[keycount].keyword,
			 strlen(rfc822_keywords[keycount].keyword))) {
		rfc822_keywords[keycount].callback(value, header);
		break;
	    }

	    keycount++;
	}
    }

    /* Curptr is the now pointing to the start of the buffer */
    /* so we can determine the offset of the message text    */

    header->offset = (int) (curptr - buffer);
    header->msgsize = (int) (totalsize - header->offset);
}

static char *marray[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
    "Aug", "Sep", "Oct", "Nov", "Dec"
};

static char *
get_month(int value)
{
    return (marray[value]);
}

static int
get_month_value(char *month)
{
    int i;

    for (i = 0; i < 12; i++)
	if (!strcmp(month, marray[i]))
	    return (i);

    return (0);
}

static char *warray[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

static char *
get_weekday(int value)
{
    return (warray[value]);
}

static int
get_weekday_value(char *wday)
{
    int i;

    for (i = 0; i < 7; i++)
	if (!strcmp(wday, warray[i]))
	    return (i);

    return (0);
}

void
rfc822_build_date(nxmail_date_t * in, char *out)
{
    sprintf(out, "%3s, %2d %3s %4d %2d:%2d:%2d",
	    get_weekday(in->wday), in->day, get_month(in->month),
	    in->year, in->hour, in->min, in->sec);
}

/* Take a date of the format [www], dd mmm yy hh:mm:ss zone +hhh */
/* and put it into a structure suitable for use by the user      */

void
rfc822_parse_date(char *date, nxmail_date_t * out)
{
    char wdaystr[3], monthstr[3];

    int day, year;
    int hour, min, sec;

    /* First, parse the date into the component pieces */
    /* We are not going to handle time zones, yet */

    sscanf(date, "%3s, %2d %3s %4d %2d:%2d:%2d", wdaystr, &day, monthstr,
	   &year, &hour, &min, &sec);

    out->month = get_month_value(monthstr);
    out->wday = get_weekday_value(wdaystr);

    if (day >= 0 && day < 31)
	out->day = day;

    if (year >= 0 && year < 3000)
	out->year = year;

    if (hour >= 0 && hour <= 24)
	out->hour = hour;

    if (min >= 0 && min <= 60)
	out->min = min;

    if (min >= 0 && min <= 60)
	out->sec = sec;
}

char *
rfc822_append_text(char *ptr, char *str)
{
    strcat(ptr, str);
    return (ptr + (strlen(str)));
}

char *
rfc822_append_field(char *ptr, char *fieldname, char *value)
{
    char outstr[1024];
    sprintf(outstr, "%s%s\n", fieldname, value);

    return (rfc822_append_text(ptr, outstr));
}

char *
rfc822_append_addrlist(char *ptr, char *field, nxmail_address_t * list)
{
    char *lptr = ptr;
    char addrstr[100];
    nxmail_address_t *alist = list;

    lptr = rfc822_append_text(lptr, field);

    while (alist) {
	rfc822_build_address(alist, addrstr);
	lptr = rfc822_append_text(lptr, addrstr);
	if (alist->next)
	    lptr = rfc822_append_text(lptr, ", ");

	alist = alist->next;
    }

    return (rfc822_append_text(lptr, "\n"));
}

int
rfc822_build_message(nxmail_header_t * header, char *body, char *output)
{
    char addrstr[100];
    char datestr[100];
    char *bufptr = output;

    /* date, from, subject, to, cc, bcc, reply to */


    rfc822_build_date(&header->date, datestr);

    bufptr = rfc822_append_field(bufptr, "Date: ", datestr);

    rfc822_build_address(&header->from, addrstr);

    bufptr = rfc822_append_field(bufptr, "From: ", addrstr);
    bufptr = rfc822_append_field(bufptr, "Subject: ", header->subject);

    bufptr = rfc822_append_addrlist(bufptr, "To: ", &header->to);

    if (strlen(header->cc.host))
	bufptr = rfc822_append_addrlist(bufptr, "cc: ", &header->cc);

    bufptr = rfc822_append_text(bufptr, "\n");
    bufptr = rfc822_append_text(bufptr, body);

    return ((int) (bufptr - output));
}

void
rfc822_ignore(char *inptr, nxmail_header_t * header)
{
    return;
}

void
rfc822_date(char *inptr, nxmail_header_t * header)
{
    rfc822_parse_date(inptr, &header->date);
    return;
}

void
rfc822_from(char *inptr, nxmail_header_t * header)
{
    /* Get the from field */
    rfc822_parse_address(&header->from, inptr);
}

void
rfc822_to(char *inptr, nxmail_header_t * header)
{
    nxmail_address_t *addrlist = &header->to;
    int count = nxmail_count_addrstr(inptr);

    if (!count)
	return;

    count = nxmail_alloc_addrlist(addrlist, count);
    nxmail_build_addrlist(inptr, addrlist, count);
}

void
rfc822_cc(char *inptr, nxmail_header_t * header)
{
    nxmail_address_t *addrlist = &header->cc;
    int count = nxmail_count_addrstr(inptr);

    if (!count)
	return;

    count = nxmail_alloc_addrlist(addrlist, count);
    nxmail_build_addrlist(inptr, addrlist, count);
}

void
rfc822_replyto(char *inptr, nxmail_header_t * header)
{
    /* Get the to field */
    strncpy(header->replyto, inptr, sizeof(header->replyto) - 1);
}

void
rfc822_subject(char *inptr, nxmail_header_t * header)
{
    strncpy(header->subject, inptr, sizeof(header->subject) - 1);
}

void
rfc822_build_address(nxmail_address_t * out, char *output)
{
    char addrstr[256];

    if (strlen(out->host))
	sprintf(addrstr, "%s@%s", out->mailbox, out->host);
    else
	sprintf(addrstr, "%s", out->mailbox);

    if (strlen(out->name)) {
	sprintf(output, "%s <%s>", out->name, addrstr);
    } else
	sprintf(output, "%s", addrstr);
}

/* These charaters cannot be in a address string */

static char addrchars[] = { '(', ')', '<', '>', ',',
    ';', '\\', '"', '[', ']', ' ',
};


static int
rfc822_verify_addr(char *addr, int len)
{
    int i;

    for (i = 0; i < len; i++) {
	int c;

	for (c = 0; c < 11; c++)
	    if (addr[i] == addrchars[c])
		return (0);
    }

    return (1);
}

char *
rfc822_parse_name(nxmail_address_t * dest, char *address)
{
    int size;
    char *ptr, *nptr;

    if (*address == '"')
	ptr = address + 1;
    else
	ptr = address;

    /* Go until we find another quote or a < */
    for (nptr = ptr; *nptr; nptr++) {
	if (*nptr == '"')
	    break;

	if (*nptr == '<')
	    break;

	/* If we find a at sign with no quotes or qualifiers, bet that */
	/* we're barking up the wrong tree */

	if (*nptr == '@' && *address != '"')	/* uhoh, its an address.  Bail! */
	    return (address);

	/* This helps ensure that we don't get caught in a loop */
	if ((int) (nptr - ptr) > sizeof(dest->name))
	    break;
    }

    /* Ok, we have some amount of name, ensure that we can fit it */
    /* into the structure without overrunning the buffer */

    size = (int) (nptr - ptr);

    if (size >= sizeof(dest->name)) {
	size = sizeof(dest->name) - 1;
    }

    if (size)
	strncpy(dest->name, ptr, size);

    return (nptr + 1);
}

char *
rfc822_parse_mailbox(nxmail_address_t * dest, char *address)
{
    char *ptr, *nptr;

    if (*address == '<')
	ptr = address + 1;
    else
	ptr = address;

    /* Go to the end */

    for (nptr = ptr; *nptr && *nptr != '>' && *nptr != ' '; nptr++);

    if (rfc822_verify_addr(ptr, (int) (nptr - ptr)) == 1) {
	/* The address checks out with no bad chars */
	/* now try to get the mailbox and host */

	char *aptr = strchr(ptr, '@');

	if (aptr) {
	    int size;

	    if ((int) (aptr - ptr) >= sizeof(dest->mailbox)) {
		size = sizeof(dest->mailbox) - 1;
	    } else {
		size = (int) (aptr - ptr);
	    }

	    strncpy(dest->mailbox, ptr, size);
	    dest->host[size + 1] = 0;

	    if ((int) (nptr - aptr - 1) >= sizeof(dest->host)) {
		size = sizeof(dest->host) - 1;
	    } else
		size = (int) (nptr - aptr - 1);

	    strncpy(dest->host, aptr + 1, size);
	    dest->host[size + 1] = 0;
	} else {
	    int size;

	    if ((int) (nptr - ptr) >= sizeof(dest->mailbox))
		size = sizeof(dest->mailbox) - 1;
	    else
		size = (int) (nptr - ptr);

	    strncpy(dest->mailbox, ptr, size);
	}

	return (nptr + 1);
    }

    /* Otherwise, something didn't come out right */
    return (address);
}

void
rfc822_parse_address(nxmail_address_t * dest, char *address)
{
    char *ptr = address;

    while (*ptr) {
	char *nptr;

	/* First, strip any whitespace */
	while (*ptr) {
	    if (*ptr != ' ' && *ptr != '\t')
		break;

	    ptr++;
	}

	if (!*ptr)
	    break;

	if (*ptr == '"' || *ptr == ' ') {
	    ptr = rfc822_parse_name(dest, ptr);
	    continue;
	}

	if (*ptr == '<') {
	    ptr = rfc822_parse_mailbox(dest, ptr);
	    continue;
	}

	nptr = rfc822_parse_name(dest, ptr);

	if (nptr != ptr) {
	    ptr = nptr;
	    continue;
	}

	ptr = rfc822_parse_mailbox(dest, ptr);
    }
}

--- NEW FILE: nxmail.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef NXMAIL_H
#define NXMAIL_H

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdio.h>

#define NXMAIL_TYPE_POP3 0
#define NXMAIL_TYPE_LAST 1

#define NXMAIL_OK            0
#define NXMAIL_SEND_OK       0

#define NXMAIL_ERROR        -1
#define NXMAIL_STREAM_OPEN  -2
#define NXMAIL_NO_STREAM    -3
#define NXMAIL_ADDR_ERROR   -4
#define NXMAIL_NET_ERROR    -5
#define NXMAIL_SEND_FAILURE -6
#define NXMAIL_SEND_ERROR   -7
#define NXMAIL_NETWORK_ERROR -8

    typedef struct
    {
	int fd;
	int type;
    }
    nxmail_stream;

    typedef struct
    {
	int (*mail_open) (char *, int, nxmail_stream *);
	int (*mail_login) (nxmail_stream *, char *, char *);
	int (*mail_status) (nxmail_stream *, int *, int *);
	int (*mail_msginfo) (nxmail_stream *, int);
	int (*mail_fetchheader) (nxmail_stream *, int, char **);
	int (*mail_fetchbody) (nxmail_stream *, int, char **);
	int (*mail_delete) (nxmail_stream *, int);
	void (*mail_close) (nxmail_stream *);
    }
    nxmail_driver_t;

    typedef struct nxmail_addr_t
    {
	char name[40];
	char mailbox[40];
	char host[40];
	int result;
	struct nxmail_addr_t *next;
    }
    nxmail_address_t;

    typedef struct
    {
	int month;
	int day;
	int year;
	int wday;

	int hour;
	int min;
	int sec;
    }
    nxmail_date_t;

    typedef struct
    {
	char type[50];
	char name[50];
	int charset;
	int encoding;
	char description[50];
    }
    nxmail_mime_header_t;

    typedef struct
    {
	/* Message variables */
	nxmail_date_t date;
	nxmail_address_t to;
	nxmail_address_t from;
	nxmail_address_t cc;
	char replyto[50];
	char subject[100];
	nxmail_mime_header_t mimeheader;

	/* Housekeeping variables */
	int offset;
	int msgsize;
    }
    nxmail_header_t;

    typedef struct nxmail_bdy_t
    {
	nxmail_mime_header_t mimeheader;
	int size;
	char *text;
	struct nxmail_bdy_t *next;
    }
    nxmail_body_t;

#define NXMAIL_ENCODING_NONE 0
#define NXMAIL_ENCODING_BASE64 1

#define NXMAIL_CHARSET_USASCII 0

    int nxmail_get_error(void);

    nxmail_stream *nxmail_init_stream(void);
    void nxmail_close_stream(nxmail_stream * stream);

    int nxmail_open(nxmail_stream * stream, char *address, int port,
		    int type);
    int nxmail_auth(nxmail_stream * stream, char *user, char *password);
    int nxmail_status(nxmail_stream * stream, int *msgcount);

    nxmail_header_t *nxmail_fetchheader(nxmail_stream * stream, int msgno);
    nxmail_body_t *nxmail_fetchbody(nxmail_stream * stream, int msgno);

    int nxmail_sendmsg(char *server, int port,
		       nxmail_header_t * header, char *body, int size);

    void nxmail_parsedate(char *rfc822_date, nxmail_date_t * date);

    int nxmail_delete(nxmail_stream * stream, int message);
    void nxmail_close(nxmail_stream * stream);

/* Various parsers that may be useful to people */
    void rfc822_parse_address(nxmail_address_t * dest, char *address);

/* Address list management */


    void nxmail_build_addrstr(nxmail_address_t * out, char *output);
    int nxmail_count_addrstr(char *addrstring);

    int nxmail_build_addrlist(char *addrstring,
			      nxmail_address_t * addrlist, int count);

    int nxmail_alloc_addrlist(nxmail_address_t * head, int count);
    void nxmail_free_addrlist(nxmail_address_t * head);

    void nxmail_parse_dateval(unsigned long, nxmail_date_t * date);

    nxmail_body_t *nxmail_alloc_body_struct(int size);
    void nxmail_free_body_struct(nxmail_body_t * head);

#ifdef __cplusplus
}
#endif

#endif

--- NEW FILE: Makefile ---
# apps/mail/nxmail/Makefile

LIB_STATIC=libnxmail.a

SRC=${shell ls *.c}
OBJS=${SRC:.c=.o}

include $(BASE_DIR)/Rules.make




--- NEW FILE: cache.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef CACHE_H
#define CACHE_H

#include "nxmail.h"

typedef struct
{
    int key;			/* The index that we search on        */
    int age;			/* The age of the entry (in accesses) */
    int size;			/* The size of the raw buffer         */

    nxmail_header_t header;	/* Parsed nxmail header */

    char *raw;			/* the raw message as it was recieved */
    nxmail_body_t *body;	/* parsed nxmail body   */

}
cache_entry_t;

void cache_init(void);
void cache_close(void);

cache_entry_t *get_new_cache_entry(int key, int size);
void free_cache_entry(cache_entry_t *);
cache_entry_t *search_cache_entry(int);

#endif

--- NEW FILE: str_util.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef STR_UTILS_H
#define STR_UTILS_H

void str_lcase(char *value, int len);
char *str_getline(char *, char *, int);

char *str_skipwhite(char *ptr);
char *str_getfield(char *in, char delim, char **field);
int str_parsefield(char *in, char delim, char **keyword, char **value);

#endif

--- NEW FILE: mail_pop3.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


/*
 * NXMAIL - MAIL_POP3.C
 * Routines to access POP3 mailboxes 
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/time.h>
#include <sys/types.h>

#include "nxmail.h"
#include "net_util.h"

#define POP3_PORT 110

static int
pop3_command(int fd, char *in, int len)
{
    int outlen;

#ifdef DEBUG
    printf("CLIENT OUT (%d):  %s", len, in);
#endif

    if (tcp_wait_for_socket(fd, 10, TCP_WRITE) <= 0)
	return (-1);

    outlen = write(fd, in, len);

    if (outlen != len) {
	if (outlen == -1)
	    perror("POP3_COMMAND (WRITE)");

	SET_NET_ERROR(errno);
	return (-1);
    }

    return (0);
}

static int
pop3_response(int fd, char *out, int len, int wait)
{
    int ret;
    int lindex;

    if (tcp_wait_for_socket(fd, 10, TCP_READ) <= 0)
	return (-1);

    ret = fdgets(fd, out, len - 1);

    if (ret <= 0) {
	printf("Got back %d from ret!\n", ret);
	return (-1);
    }

    /* Strip the CRLF and just turn it into a CR */
    lindex = (strlen(out) - 1);

    if (out[lindex] == '\n' && out[lindex - 1] == '\r') {
	out[lindex - 1] = '\n';
	out[lindex] = 0;
    }
#ifdef DEBUG
    printf("CLIENT IN: %s", out);
#endif

    return (0);
}

#ifdef LOG
#define pop3_log(str)  fprintf(stderr, "LOG %s", str)
#else
#define pop3_log(str)
#endif

static int
pop3_do_command(nxmail_stream * stream, char *command,
		char *response, int reslen)
{
    int cmdlen = strlen(command);

    if (pop3_command(stream->fd, command, cmdlen) == -1)
	return (NXMAIL_NETWORK_ERROR);

    if (pop3_response(stream->fd, response, reslen, 1) == -1)
	return (NXMAIL_NETWORK_ERROR);

#ifdef LOG
    pop3_log(response);
#endif

    return (NXMAIL_OK);
}

static int
pop3_is_ok(char *response)
{
    if (response[0] == '+')
	return (1);
    else
	return (0);
}

static int
pop3_get_data(nxmail_stream * stream, char *buffer, int maxlen)
{
    char *pos = buffer;
    int copied = 0;

    char linebuf[1024];

    while (1) {
	char *lpos = 0;
	int lsize = 0;

	if (pop3_response(stream->fd, linebuf, 1024, 0) != NXMAIL_OK)
	    break;

	if (!strlen(linebuf))
	    break;
	if (!strcmp(linebuf, ".\n"))
	    break;

	lpos = linebuf;
	lsize = strlen(linebuf);

	if (linebuf[0] == '.') {
	    lpos++;
	    lsize--;
	}

	if (copied + lsize > maxlen) {
	    strncpy(pos, lpos, maxlen - copied);
	    break;
	}

	strncpy(pos, lpos, lsize);

	pos += lsize;
	copied += lsize;
    }

    return (copied);
}

int
pop3_open(char *address, int port, nxmail_stream * stream)
{
    char response[200];
    int res;
    int fd = tcp_open_stream(address, port);

    if (fd == -1)
	return (NXMAIL_NETWORK_ERROR);

    stream->fd = fd;

    /* Now wait for the server to respond */
    res = pop3_response(stream->fd, response, 200, 1);

    if (res == -1) {
	close(fd);
	stream->fd = 0;
	return (NXMAIL_NETWORK_ERROR);
    }
#ifdef DEBUG
    pop3_log(response);
#endif

    return (NXMAIL_OK);
}

int
pop3_login(nxmail_stream * stream, char *user, char *password)
{
    char command[100];
    char response[100];

    /* Send the user string */

#ifdef DEBUG
    printf("LOG: Sending USER command\n");
#endif

    sprintf(command, "USER %s\n", user);

    pop3_do_command(stream, command, response, 100);

    if (!pop3_is_ok(response))
	return (NXMAIL_ERROR);

#ifdef DEBUG
    printf("LOG: Sending PASS command\n");
#endif

    sprintf(command, "PASS %s\n", password);

    pop3_do_command(stream, command, response, 100);

    if (!pop3_is_ok(response))
	return (NXMAIL_ERROR);

    return (NXMAIL_OK);
}

void
pop3_close(nxmail_stream * stream)
{
    char response[10];

    if (stream->fd != 0) {
	pop3_do_command(stream, "QUIT\n", response, 10);

	close(stream->fd);
	stream->fd = 0;
    }

}

int
pop3_stat(nxmail_stream * stream, int *msgcount, int *msgsize)
{
    char response[100];

    pop3_do_command(stream, "STAT\n", response, 100);

    if (!pop3_is_ok(response))
	return (NXMAIL_ERROR);

    sscanf(response, "+OK %d %d", msgcount, msgsize);
    return (NXMAIL_OK);
}

int
pop3_msginfo(nxmail_stream * stream, int msg)
{
    char command[100];
    char response[100];
    int tmp, msgsize;

    sprintf(command, "LIST %d\n", msg);

    pop3_do_command(stream, command, response, 100);

    if (!pop3_is_ok(response))
	return (NXMAIL_ERROR);

    sscanf(response, "+OK %d %d", &tmp, &msgsize);
    return (msgsize);
}

/* This just gets the header, nice for those quick grabs */
/* Returns the read size of the buffer */

int
pop3_getheader(nxmail_stream * stream, int msg, char **buffer)
{
    char command[100];
    char response[100];

    int hsize;

    hsize = pop3_msginfo(stream, msg);

    sprintf(command, "TOP %d 0\n", msg);

    if (pop3_command(stream->fd, command, strlen(command)) == -1)
	return (NXMAIL_NETWORK_ERROR);

    if (pop3_response(stream->fd, response, 100, 1) == -1)
	return (NXMAIL_NETWORK_ERROR);

    if (!pop3_is_ok(response))
	return (NXMAIL_ERROR);

    /* sscanf(response, "+OK %d", &hsize); */

    *buffer = (char *) malloc(hsize);
    if (!*buffer)
	return (NXMAIL_ERROR);

    return (pop3_get_data(stream, *buffer, hsize));
}

int
pop3_getbody(nxmail_stream * stream, int msg, char **buffer)
{
    char command[100];
    char response[100];
    int hsize;

    hsize = pop3_msginfo(stream, msg);

    /* Get the message */
    sprintf(command, "RETR %d\n", msg);

    if (pop3_command(stream->fd, command, strlen(command)) == -1)
	return (NXMAIL_NETWORK_ERROR);

    if (pop3_response(stream->fd, response, 100, 1) == -1)
	return (NXMAIL_NETWORK_ERROR);

    if (!pop3_is_ok(response))
	return (NXMAIL_ERROR);

    /* sscanf(response, "+OK %d", &hsize); */

    /* Local buffer ensures that we have a big enough area */
    /* to copy in a message with no breaks in it */

    *buffer = (char *) malloc(hsize);

    if (!*buffer)
	return (NXMAIL_ERROR);

    return (pop3_get_data(stream, *buffer, hsize));
}

int
pop3_delete(nxmail_stream * stream, int msg)
{
    char command[100];
    char response[100];

    sprintf(command, "DELE %d\n", msg);

    pop3_do_command(stream, command, response, 100);

    if (!pop3_is_ok(response))
	return (NXMAIL_ERROR);
    return (NXMAIL_OK);
}

/* This is the structure that the main API accesses to do POP3 functions */

nxmail_driver_t nxmail_pop3_driver = {
    pop3_open,
    pop3_login,
    pop3_stat,
    pop3_msginfo,
    pop3_getheader,
    pop3_getbody,
    pop3_delete,
    pop3_close
};

--- NEW FILE: mime.h ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#ifndef MIME_H
#define MIME_H

#include <string.h>

void mime_parse_message(char *, int, nxmail_header_t *, nxmail_body_t **);

#endif

--- NEW FILE: nxmail.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "nxmail.h"
#include "rfc822.h"
#include "mime.h"
#include "cache.h"
#include "mail_smtp.h"
#include "net_util.h"

extern nxmail_driver_t nxmail_pop3_driver;

static nxmail_driver_t *drivers[] = { &nxmail_pop3_driver };

static nxmail_stream nxmail_openstream;

int
nxmail_get_error(void)
{
    return (GET_NET_ERROR);
}

/* This will initalize the stream and get the cache ready to go */

nxmail_stream *
nxmail_init_stream(void)
{
    cache_init();
    bzero(&nxmail_openstream, sizeof(nxmail_openstream));
    return (&nxmail_openstream);
}

void
nxmail_close_stream(nxmail_stream * stream)
{
    nxmail_close(stream);
    cache_close();
    bzero(&nxmail_openstream, sizeof(nxmail_openstream));
}

int
nxmail_open(nxmail_stream * stream, char *address, int port, int type)
{
    int ret;

    if (type > NXMAIL_TYPE_LAST)
	return (0);

    ret = drivers[type]->mail_open(address, port, stream);

    if (ret == NXMAIL_NETWORK_ERROR)
	return (NXMAIL_ERROR);

    stream->type = type;

    return (ret);
}

int
nxmail_delete(nxmail_stream * stream, int msgno)
{
    if (!stream)
	return (NXMAIL_NO_STREAM);

    if (stream->fd == 0)
	return (NXMAIL_NO_STREAM);

    return (drivers[stream->type]->mail_delete(stream, msgno));
}

int
nxmail_auth(nxmail_stream * stream, char *user, char *password)
{
    if (!stream)
	return (NXMAIL_NO_STREAM);

    if (stream->fd == 0)
	return (NXMAIL_NO_STREAM);

    return (drivers[stream->type]->mail_login(stream, user, password));
}

int
nxmail_status(nxmail_stream * stream, int *msgcount)
{
    int msize, ret;

    if (!stream)
	return (NXMAIL_NO_STREAM);

    if (stream->fd == 0)
	return (NXMAIL_NO_STREAM);

    ret = drivers[stream->type]->mail_status(stream, msgcount, &msize);

    return (ret);
}


static cache_entry_t *
nxmail_retheader(nxmail_stream * stream, int msgno)
{
    cache_entry_t *centry;
    int size;
    char *buffer;

    /* Get the header only */
    size = drivers[stream->type]->mail_fetchheader(stream, msgno, &buffer);

    /* Now allocate a cache entry and put it in */
    if ((centry = get_new_cache_entry(msgno, size)) != NULL) {
	/* Copy over what we have into the raw portion */
	memcpy(centry->raw, buffer, size);

	/* Parse the header */
	rfc822_parse_header(centry->raw, &centry->header, size);
    }
    /* end of if */
    free(buffer);
    return (centry);
}

void
nxmail_parse_full(cache_entry_t * centry)
{
    mime_parse_message(centry->raw, centry->size, &centry->header,
		       &centry->body);
}

/* Retrieve the message, and parse the header */

static cache_entry_t *
nxmail_retbody(nxmail_stream * stream, int msgno)
{
    cache_entry_t *centry = search_cache_entry(msgno);

    char *buffer;
    int size;

    if (!stream)
	return (0);
    if (stream->fd == 0)
	return (0);

    size = drivers[stream->type]->mail_fetchbody(stream, msgno, &buffer);

    /* If the cache already exists, then reuse it */

    if (centry) {
	/* Free the raw space and replace it */
	if (centry->raw)
	    free(centry->raw);
	centry->raw = (char *) malloc(size);
	centry->size = size;
    } else {
	centry = get_new_cache_entry(msgno, size);
    }

    if (!centry)
	return (0);

    memcpy(centry->raw, buffer, size);

    /* Reparse the header */
    rfc822_parse_header(centry->raw, &centry->header, size);
    nxmail_parse_full(centry);

    free(buffer);
    return (centry);
}

/* Given cache entry, parse out the full message */



/* We don't normally cache headers, but if it exists, then use it */

nxmail_header_t *
nxmail_fetchheader(nxmail_stream * stream, int msgno)
{
    cache_entry_t *entry = search_cache_entry(msgno);

    /* Check the cache to see if this message already exists */
    if (!entry)
	entry = nxmail_retheader(stream, msgno);
    if (!entry)
	return (0);

    return (&entry->header);
}

nxmail_body_t *
nxmail_fetchbody(nxmail_stream * stream, int msgno)
{
    cache_entry_t *entry = search_cache_entry(msgno);

    if (!entry || !entry->body)
	entry = nxmail_retbody(stream, msgno);

    if (!entry)
	return (0);
    return (entry->body);
}

void
nxmail_parsedate(char *rfc822_date, nxmail_date_t * date)
{
    rfc822_parse_date(rfc822_date, date);
}

void
nxmail_close(nxmail_stream * stream)
{
    if (!stream)
	return;

    drivers[stream->type]->mail_close(stream);
}

int
nxmail_sendmsg(char *server, int port,
	       nxmail_header_t * header, char *body, int size)
{
    int ret;
    int outsize;
    char *output;

    /* I'm not happy about this, but for now, this will work */
    /* Allocate an extra 1K for the header                   */

    output = (char *) calloc(size + 1024, 1);

    if (!output)
	return (NXMAIL_ERROR);

    outsize = rfc822_build_message(header, body, output);

    ret = smtp_send_message(server, port, header, output, outsize);
    free(output);
    return (ret);
}

int
nxmail_count_addrstr(char *addrstring)
{
    char *startptr = addrstring;
    int count = 0;

    if (*startptr)
	count = 1;
    else
	return (0);

    while (1) {
	for (; *startptr != ',' && *startptr; startptr++);
	if (!*startptr++)
	    return (count);

	count++;
    }
}

int
nxmail_build_addrlist(char *addrstring, nxmail_address_t * addrlist,
		      int count)
{
    nxmail_address_t *addr = addrlist;
    char *startptr = addrstring;
    char *endptr;
    int i;

    for (i = 0; i < count; i++) {
	char str[100];

	bzero(str, 100);

	sscanf(startptr, "%[^,],", str);

	if (!strlen(str))
	    return (i);

	/* bzero(addr, sizeof(nxmail_address_t)); */

	rfc822_parse_address(addr, str);

	endptr = (startptr + strlen(str) + 1);

	if (!*endptr)
	    return (i + 1);
	for (; *endptr == ' ' && *endptr; endptr++);
	if (!*endptr)
	    return (i + 1);

	if (addr->next)
	    addr = addr->next;
	else
	    return (i + 1);
	startptr = endptr;
    }

    return (count);
}

int
nxmail_alloc_addrlist(nxmail_address_t * head, int count)
{
    int i;

    /* The first entry (the head) is always static, so only */
    /* allocate memory if there is more than 1 address      */

    if (count == 1)
	return (1);

    for (i = 1; i < count; i++) {
	head->next = (nxmail_address_t *) calloc(sizeof(nxmail_address_t), 1);

	if (!head->next)
	    return (i);

	head = head->next;
    }

    return (count);
}

void
nxmail_free_addrlist(nxmail_address_t * head)
{
    nxmail_address_t *ptr = head->next;
    nxmail_address_t *nptr;

    while (ptr) {
	nptr = ptr->next;
	free(ptr);
	ptr = nptr;
    }
}

void
nxmail_parse_dateval(unsigned long seconds, nxmail_date_t * date)
{
    struct tm *tm = localtime(&seconds);

    date->wday = tm->tm_wday;
    date->day = tm->tm_mday;
    date->month = tm->tm_mon;
    date->year = (tm->tm_year + 1900);

    date->hour = tm->tm_hour;
    date->min = tm->tm_min;
    date->sec = tm->tm_sec;
}

nxmail_body_t *
nxmail_alloc_body_struct(int size)
{
    nxmail_body_t *ptr = (nxmail_body_t *) calloc(sizeof(nxmail_body_t), 1);
    if (!ptr)
	return (0);

    ptr->size = size;
    ptr->next = 0;

    return (ptr);
}

void
nxmail_free_body_struct(nxmail_body_t * head)
{
    nxmail_body_t *ptr = head;

    while (ptr) {
	nxmail_body_t *nptr = ptr->next;
	free(ptr);
	ptr = nptr;
    }
}

--- NEW FILE: str_util.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <string.h>

static inline int
isspace(char test)
{
    return ((test == ' ' || test == '\t'));
}

/* Turn the given string into lower case */

void
str_lcase(char *value, int len)
{
    int i;

    for (i = 0; i < len; i++)
	if (value[i] >= 65 && value[i] <= 90)
	    value[i] = value[i] + 32;
}

char *
str_skipwhite(char *ptr)
{
    while (isspace(*ptr) && *ptr)
	ptr++;
    return (ptr);
}

/* WARNING:  THIS MANGLES THE STRING */
char *
str_getfield(char *in, char delim, char **field)
{
    char *ptr = in;

    ptr = str_skipwhite(ptr);

    if (!*ptr) {
	*field = 0;
	return (0);
    }

    *field = ptr;

    /* Now advance until the delim */
    while (*ptr != delim && *ptr)
	ptr++;

    if (*ptr) {
	*ptr = 0;
	if (*(ptr + 1))
	    return (ptr + 1);
    }

    return (0);
}

/* Given a buffer, parse off the keyword and value */
/* WARNING:  THIS MANGLES THE STRING */

int
str_parsefield(char *in, char delim, char **keyword, char **value)
{
    char *ptr = in;

    ptr = str_skipwhite(ptr);

    if (!*ptr)
	return (0);		/* Nothing found */

    *keyword = ptr;

    /* Now advance until the delim */
    while (*ptr != delim && ptr)
	ptr++;

    if (!*ptr)
	return (0);

    *ptr = 0;

    ptr = str_skipwhite(ptr + 1);

    if (!*ptr)
	return (0);

    *value = ptr;
    return (1);
}


/* This copies the string, but it does not mangle it! */

char *
str_getline(char *in, char *out, int outsize)
{
    char *inpos = in;
    char *outpos = out;

    int copied = 0;

    /* Zero out the whole buffer */
    bzero(out, outsize);

    while (*inpos) {
	int linesize = 0;
	char *curpos = inpos;

	/* Find the end of the current line */
	while (*curpos != '\n' && *curpos)
	    curpos++;

	/* Calculate the size of the line */
	linesize = (int) (curpos - inpos);

	/* If the total size of the string is greater than the input, then copy as much as we can */

	if (copied + linesize >= outsize) {
	    strncpy(outpos, inpos, outsize - copied);
	    return (curpos + 1);	/* And return */
	}

	/* Otherwise, attach the string */
	strncpy(outpos, inpos, linesize);

	curpos++;
	if (!*curpos)
	    return (0);		/* Nothing more to see here */

	/* If it is not white space, then this is a new line */
	if (!isspace(*curpos))
	    return (curpos);

	/* If there was whitespace, then this is a continued line, so add it on */

	/* Turn tabs into spaces */
	for (; *curpos && *curpos == '\t'; curpos++)
	    *curpos = ' ';

	inpos = curpos;

	outpos += linesize;
	copied += linesize;
    }

    return (0);
}

--- NEW FILE: cache.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


/*
 * This manages a simple cache that holds the last 
 * few messages that were accessed 
 */

#define CACHE_SIZE 5

#include <stdlib.h>
#include <string.h>
#include "cache.h"

static cache_entry_t cache_entry[5];

int
get_oldest_entry()
{
    int useentry = -1;
    int oldest = -1;
    int age = 0;
    int i;

    for (i = 0; i < CACHE_SIZE; i++) {
	/* If the age is too high, then it must be corrupted */

	if (cache_entry[i].age > 1000) {
	    bzero(&cache_entry[i], sizeof(cache_entry));
	    cache_entry[i].age = -1;
	}

	if (cache_entry[i].age == -1) {
	    if (useentry == -1)
		useentry = i;
	} else {
	    cache_entry[i].age++;

	    if (cache_entry[i].age > age) {
		age = cache_entry[i].age;
		oldest = i;
	    }
	}
    }

    if (useentry != -1)
	return (useentry);
    return (oldest);
}


cache_entry_t *
search_cache_entry(int key)
{
    int i;

    for (i = 0; i < CACHE_SIZE; i++) {
	if (cache_entry[i].key == key)
	    return (&cache_entry[i]);
    }

    return (0);
}

void
free_cache_entry(cache_entry_t * entry)
{
    if (entry->raw)
	free(entry->raw);

    nxmail_free_addrlist(&entry->header.to);

    nxmail_free_addrlist(&entry->header.cc);

    nxmail_free_body_struct(entry->body);

    bzero(entry, sizeof(cache_entry_t));
    entry->age = -1;
}

/* The size is the size of the raw message */

cache_entry_t *
get_new_cache_entry(int key, int size)
{
    /* Grab the oldest entry */
    int entry = get_oldest_entry();

    /* If it was being used, then free it */
    if (cache_entry[entry].age != -1)
	free_cache_entry(&cache_entry[entry]);

    /* Now, allocate some space for the raw message */
    cache_entry[entry].raw = (char *) calloc(size + 1, 1);

    if (!cache_entry[entry].raw)
	return (0);

    cache_entry[entry].age = 0;
    cache_entry[entry].size = size;
    cache_entry[entry].key = key;
    cache_entry[entry].body = 0;

    return (&cache_entry[entry]);
}

void
cache_init(void)
{
    int i;

    for (i = 0; i < CACHE_SIZE; i++) {
	bzero(&cache_entry[i], sizeof(cache_entry_t));
	cache_entry[i].age = -1;
    }
}


void
cache_close(void)
{
    int i;

    for (i = 0; i < CACHE_SIZE; i++)
	free_cache_entry(&cache_entry[i]);

}

--- NEW FILE: mime.c ---
/*                                                                       
 * Copyright (c) 2003 Century Software, Inc.   All Rights Reserved.     
 *                                                                       
 * This file is part of the PIXIL Operating Environment                 
 *                                                                       
 * The use, copying and distribution of this file is governed by one    
 * of two licenses, the PIXIL Commercial License, or the GNU General    
 * Public License, version 2.                                           
 *                                                                       
 * Licensees holding a valid PIXIL Commercial License may use this file 
 * in accordance with the PIXIL Commercial License Agreement provided   
 * with the Software. Others are governed under the terms of the GNU   
 * General Public License version 2.                                    
 *                                                                       
 * This file may be distributed and/or modified under the terms of the  
 * GNU General Public License version 2 as published by the Free        
 * Software Foundation and appearing in the file LICENSE.GPL included   
 * in the packaging of this file.                                      
 *                                                                       
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING  
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A            
 * PARTICULAR PURPOSE.                                                  
 *                                                                       
 * RESTRICTED RIGHTS LEGEND                                             
 *                                                                     
 * Use, duplication, or disclosure by the government is subject to      
 * restriction as set forth in paragraph (b)(3)(b) of the Rights in     
 * Technical Data and Computer Software clause in DAR 7-104.9(a).       
 *                                                                      
 * See http://www.pixil.org/gpl/ for GPL licensing       
 * information.                                                         
 *                                                                      
 * See http://www.pixil.org/license.html or              
 * email cetsales at centurysoftware.com for information about the PIXIL   
 * Commercial License Agreement, or if any conditions of this licensing 
 * are not clear to you.                                                
 */


#include <stdlib.h>
#include <string.h>

#include "nxmail.h"
#include "rfc822.h"
#include "mime.h"
#include "str_util.h"

/* This is a local structure that holds all of the mime information */
/* that the client may not care about.  This cuts down on each      */
/* body section carrying around a huge mime header structure that   */
/* is basically useless                                             */

typedef struct
{
    char type[50];
    char bound[100];
    char name[50];
    char description[50];

    int encoding;
    int charset;
}
local_mimeheader_t;

/* These are all of the possible 1.1 MIME fields.  Most we can ignore, but those we care about */


static char *
mime_find_next_section(char *buffer, char *boundary)
{
    char linebuf[1024];
    char *curptr = buffer;

    while (1) {
	char *nextptr;

	if (!curptr)
	    return (0);		/* Nothing there, bail */

	/* Grab the line and strip the endline */
	nextptr = str_getline(curptr, linebuf, 1024);

	/* Jump in two dashes */

	if (linebuf[0] == '-' && linebuf[1] == '-') {
	    if (!strncmp(linebuf + 2, boundary, strlen(boundary))) {
		/* It is a boundary.  Is it the last one? */

		if (linebuf[2 + strlen(boundary)] == '-')
		    return (0);
		else
		    return (curptr);
	    }
	}

	curptr = nextptr;
    }
}

void
mime_ignore(char *inptr, local_mimeheader_t * header)
{
    return;
}

void
mime_description(char *inptr, local_mimeheader_t * header)
{
    strncpy(header->description, inptr, 50);
}

void
mime_contentEncoding(char *inptr, local_mimeheader_t * header)
{
    /* Determine the various encoding schemes here */
    /* Right now we only handle BASE64 */

    str_lcase(inptr, strlen(inptr));

    if (!strncmp(inptr, "base64", strlen("base64")))
	header->encoding = NXMAIL_ENCODING_BASE64;
    else
	header->encoding = NXMAIL_ENCODING_NONE;

    return;
}

void
mime_charset(char *inptr, local_mimeheader_t * header)
{
}

void
mime_boundary(char *inptr, local_mimeheader_t * header)
{
    /* Watch out for the quotes! */

    char *ptr = inptr + 1;

    /* Look for the other quote, igoring any escaped quotes */

    while (*ptr) {
	if (*ptr == '"' && *(ptr - 1) != '\\')
	    break;
	ptr++;
    }

    if (!*ptr)
	return;

    strncpy(header->bound, inptr + 1, (int) (ptr - inptr) - 1);
}

void
mime_name(char *inptr, local_mimeheader_t * header)
{
    strncpy(header->name, inptr, 50);
}

struct
{
    char keyword[10];
    void (*callback) (char *, local_mimeheader_t * header);
}
content_keyword[] =
{
    {
    "charset", mime_charset}
    , {
    "name", mime_name}
    , {
    "boundary", mime_boundary}
    , {
    "<none>", 0}
};

/* Stupid content type has a million entries all it own, so we need */
/* to do parsing within parsing */

void
mime_contentType(char *inptr, local_mimeheader_t * header)
{
    char *field;
    char *curptr;

    /* Get the first entry, which is the content type */

    curptr = str_getfield(inptr, ';', &field);

    if (field)
	strcpy(header->type, field);
    str_lcase(header->type, strlen(header->type));

    /* Now, parse the other items */
    while (curptr) {
	char *keyword, *value;

	curptr = str_getfield(curptr, ';', &field);

	if (str_parsefield(field, '=', &keyword, &value)) {
	    int count = 0;
	    str_lcase(keyword, strlen(keyword));

	    /* Go through the content keywords */

	    while (content_keyword[count].callback) {
		if (!strncmp(keyword, content_keyword[count].keyword,
			     strlen(content_keyword[count].keyword))) {
		    content_keyword[count].callback(value, header);
		    break;
		}

		if (content_keyword[count].callback == 0)
		    break;

		count++;
	    }
	}
    }

    return;
}

struct
{
    char keyword[30];
    void (*callback) (char *, local_mimeheader_t * header);
}
mime_keywords[] =
{
    {
    "--", mime_ignore}
    , {
    "accept", mime_ignore}
    , {
    "accept-charset", mime_ignore}
    , {
    "accept-encoding", mime_ignore}
    , {
    "accept-language", mime_ignore}
    , {
    "accept-ranges", mime_ignore}
    , {
    "authorization", mime_ignore}
    , {
    "cache-control", mime_ignore}
    , {
    "connection", mime_ignore}
    , {
    "content-encoding", mime_contentEncoding}
    , {
    "content-length", mime_ignore}
    , {
    "content-range", mime_ignore}
    , {
    "content-transfer-encoding", mime_contentEncoding}
    , {
    "content-type", mime_contentType}
    , {
    "content-description", mime_description}
    , {
    "digest-MessageDigest", mime_ignore}
    , {
    "keep-alive", mime_ignore}
    , {
    "link", mime_ignore}
    , {
    "location", mime_ignore}
    , {
    "max-forwards", mime_ignore}
    , {
    "mime-version", mime_ignore}
    , {
    "pragma", mime_ignore}
    , {
    "protocol", mime_ignore}
    , {
    "protocol-info", mime_ignore}
    , {
    "protocol-request", mime_ignore}
    , {
    "proxy-authenticate", mime_ignore}
    , {
    "proxy-authorization", mime_ignore}
    , {
    "public", mime_ignore}
    , {
    "range", mime_ignore}
    , {
    "referer", mime_ignore}
    , {
    "retry-after", mime_ignore}
    , {
    "server", mime_ignore}
    , {
    "trailer", mime_ignore}
    , {
    "transfer-encoding", mime_ignore}
    , {
    "upgrade", mime_ignore}
    , {
    "user-agent", mime_ignore}
    , {
    "vary", mime_ignore}
    , {
    "via", mime_ignore}
    , {
    "warning", mime_ignore}
    , {
    "www-authenticate", mime_ignore}
    , {
    "authentication-info", mime_ignore}
    , {
    "proxy-authentication-info", mime_ignore}
    , {
    "<none>", 0}
};

char *
mime_parse_header(char *input, local_mimeheader_t * header)
{
    char linebuf[1024];

    char *keyword, *value;

    char *pos = input;

    while (pos) {
	int count = 0;

	if (!pos)
	    return (0);		/* Nothing there, bail out early */

	/* Get the line from the input buffer */
	pos = str_getline(pos, linebuf, 1024);

	if (strlen(linebuf) == 0)
	    break;

	/* Parse it */
	if (str_parsefield(linebuf, ':', &keyword, &value)) {
	    str_lcase(keyword, strlen(keyword));

	    while (mime_keywords[count].callback) {
		if (!strncmp(keyword, mime_keywords[count].keyword,
			     strlen(mime_keywords[count].keyword))) {
		    mime_keywords[count].callback(value, header);
		    break;
		}

		count++;
	    }
	}
    }

    return (pos);
}

nxmail_body_t *
mime_parse_section(char *input, int sectionsize, local_mimeheader_t * header)
{
    local_mimeheader_t localheader;

    nxmail_body_t *body;
    char *bodyptr;

    bzero(&localheader, sizeof(local_mimeheader_t));

    /* Create a body structure */
    body = nxmail_alloc_body_struct(sectionsize);

    if (!body)
	return (0);

    /* Now, check out the section header */
    bodyptr = mime_parse_header(input, &localheader);

    if (!bodyptr) {
	free(body);
	return (0);
    }

    /* Store the mime information */

    strcpy(body->mimeheader.type, localheader.type);
    strcpy(body->mimeheader.description, localheader.description);
    strcpy(body->mimeheader.name, localheader.name);

    body->mimeheader.encoding = localheader.encoding;
    body->mimeheader.charset = localheader.charset;

    body->text = bodyptr;
    body->size = (input + sectionsize) - bodyptr;
    return (body);
}

/* This function parses the given message into a series of body sections for each mime type */
void
mime_parse_message(char *message, int msgsize, nxmail_header_t * header,
		   nxmail_body_t ** body)
{
    char *curptr = message;
    local_mimeheader_t localheader;

    bzero(&localheader, sizeof(local_mimeheader_t));

    /* Step 1:  Go through the main header again, looking for mime related keywords */

    curptr = mime_parse_header(curptr, &localheader);

    /* The curptr should be pointing at the start of the message, but we're going to cheat */
    /* and grab the offset from the nxmail_header_t, just to be safe */

    curptr = message + header->offset;

    /* Easiest case.  No mime encoding at all.  Call it a text/plain and bail */

    if (!strlen(localheader.type)) {
	int size;

	nxmail_body_t *bodyptr;

	sprintf(header->mimeheader.type, "text/plain");

	header->mimeheader.encoding = NXMAIL_ENCODING_NONE;
	header->mimeheader.charset = NXMAIL_CHARSET_USASCII;

	size = (int) (header->msgsize);

	bodyptr = *body = nxmail_alloc_body_struct(size);

	bodyptr->size = size;
	bodyptr->text = curptr;
	return;
    }

    /* MIME encoding was specified.  If the mimetype is not multipart/, then */
    /* assume its all one big happy message */

    if (strncmp(localheader.type, "multipart", strlen("multipart"))) {
	int size;
	nxmail_body_t *bodyptr;

	strcpy(header->mimeheader.type, localheader.type);

	header->mimeheader.encoding = localheader.encoding;
	header->mimeheader.charset = localheader.charset;

	size = (int) (header->msgsize);
	bodyptr = *body = nxmail_alloc_body_struct(size);

	bodyptr->size = size;
	bodyptr->text = curptr;
	return;
    }

    /* So its a multipart message.  Find the first section */

    curptr = mime_find_next_section(curptr, localheader.bound);

    /* No message.  Thats not right.... */

    while (1) {
	char linebuf[1024];
	char *nextptr;
	nxmail_body_t *section = 0;
	int size = 0;

	if (!curptr)
	    return;

	/* First order of business, get rid of the boundary line */
	curptr = str_getline(curptr, linebuf, 1024);

	if (!curptr)
	    return;

	/* Now find the next section */

	nextptr = mime_find_next_section(curptr, localheader.bound);

	if (!nextptr)
	    size = (int) ((message + msgsize) - curptr);
	else
	    size = (int) (nextptr - curptr);

	/* Now parse the section */

	if (!*body) {
	    *body = mime_parse_section(curptr, size, &localheader);
	    section = *body;
	} else {
	    section->next = mime_parse_section(curptr, size, &localheader);
	    if (section->next)
		section = section->next;
	}

	/* Go back around for the next section */
	curptr = nextptr;
    }
}




More information about the dslinux-commit mailing list