/* this is libspopc.h file.
 * this is part of the libspopc library sources
 * copyright © 2002 Benoit Rouits <brouits@free.fr>
 * released under the terms of GNU LGPL
 * (GNU Lesser General Public Licence).
 * libspopc offers simple API for a pop3 client (MDA).
 * See RFC 1725 for pop3 specifications.
 * more information on http://brouits.free.fr/libspopc/
 */
#ifndef LIBSPOPC_H
#define LIBSPOPC_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#ifdef WIN32
#include <winsock.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#endif


#ifdef USE_SSL

#include <openssl/ssl.h>

/******************************************************************************
 * If compiled with SSL support, the low-level functions will act on a 
 * "pop3sock" structure, which contains the socket, SSL instance and context 
 * for the connection. This structure is dynamically allocated and initialized 
 * when you do pop3_prepare() or popbegin(), and is cleaned-up and destroyed in 
 * pop3_disconnect() or popend().
 ******************************************************************************/

typedef struct {
        int sock;
        SSL *ssl;
        SSL_CTX *ctx;
} pop3sock;

typedef pop3sock* pop3sock_t;

#define BAD_SOCK NULL


/******************************************************************************
 * Use pop3_cert_setup() to specify the location of your SSL certificate
 * bundle. If it is not set (or set to NULL), SSL connections can be still be 
 * made, but certificates will not be verified!
 * This function sets a global variable, and should be called before 
 * pop3_prepare() or popbegin() if you want to verify certs.
 * 
 * Hint: If you have a recent version of curl/libcurl installed, you can try 
 * setting this to the output of:  "curl-config --ca"
 ******************************************************************************/
void pop3_cert_setup(char *certfile);



#else /* Non-SSL */

/******************************************************************************
 *  If the library is compiled without SSL, the "pop3sock_t" type is a simple
 *  integer (i.e. socket) and all the functions should work just as they did
 *  in previous libspopc versions.
 ******************************************************************************/

typedef int pop3sock_t;


#define BAD_SOCK -1

#endif /* SSL */


/***************************************
 * low-level methods for a pop3 client *
 ***************************************/
#define SOCKET_TIMEOUT 15
#define TCPBUFLEN 512
/******************************************************************************
 * Be careful, using the low-level API is uncompliant with using the high     
 * level API. Here, you make your choice. If you don't know the pop3 protocol 
 * or what a socket is, it is then warmly recommended to use the *high-level* 
 * API if which is shown far below on this file.                              
 ******************************************************************************/

/**************
 * connecting *
 **************/

pop3sock_t pop3_prepare(const char* servername, const int port, struct sockaddr_in* connection, struct hostent* server);
/* prepares the pop session and returns a socket descriptor, or BAD_SOCK on error */

char* pop3_connect(pop3sock_t sock, struct sockaddr_in* connection);
/* connects to the server through the sock and returns server's welcome */

void pop3_disconnect(pop3sock_t sock);
/* close socket  */


/****************
 * pop3 queries *
 ****************/

char* pop3_user(pop3sock_t sock, const char* name);
/* performs "USER" pop query and returns server's <512 bytes response */

char* pop3_pass(pop3sock_t sock, const char* pw);
/* performs "PASS" pop query and return server's <512 bytes response */

char* pop3_quit(pop3sock_t sock);
/* performs "QUIT" pop query and returns server's <512 bytes response */

char* pop3_stat(pop3sock_t sock);
/* performs "STAT" pop query and returns server's <512 bytes response */


char* pop3_list(pop3sock_t sock, int id);
/* performs a "LIST" pop query and returns server's (long) response */

char* pop3_retr(pop3sock_t sock, int id);
/* performs a "RETR" pop query and returns server's (long) response */

char* pop3_dele(pop3sock_t sock, int id);
/* performs a "DELE" pop query and returns server's <512 bytes response */

char* pop3_noop(pop3sock_t sock);
/* performs a "NOOP" pop query and returns server's <512 bytes response */

char* pop3_rset(pop3sock_t sock);
/* performs a "RSET" pop query and returns server's <512 bytes response */

char* pop3_top(pop3sock_t sock, int id, int lines);
/* performs a "TOP" pop query and returns server's (long) response */

char* pop3_uidl(pop3sock_t sock, int id);
/* performs a "UIDL" pop query and returns server's (long) response */

char* pop3_apop(pop3sock_t sock, const char* name, const char* digest);
/* performs a "APOP" secure pop query and returns server's <512 bytes response */


/*********************
 * parsing utilities *
 *********************/
#define DOTBEGIN(s) ((s)[0]=='\n'&&(s)[1]=='.')

int dotline(char* buf);
/* returns 1 if buf contains a "\n.\n" or "\n.\0" or \r.(etc) substring */
/* buf must be terminated by '\0' */

int pop3_error(char* string);
/* returns 1 if pop server error reply (i.e : -ERR ...) */

/************************************
 * reply re-formatting, after query *
 ************************************/
char* nextline(char* string);
/* returns a pointer to the next line of given string */

char* retr2msg(char* data);
/* returns formatted mail from a pop RETR X query */
/* must only be called on data returned by pop3_retr() */

void freemsg(char* msg);
/* free the message received by reetr2msg */

int* list2array(char* poplist);
/* WARNING: must not be called after a mail deletion */
/* returns an int array of sizes of messages from a LIST pop query */
/* array[0] holds id of the array's last element */
/* must only be called on data received by a pop3_list(sock,0) request */

void freelistarray(int* array);
/* free the message sizes array created by list2array */

int listi2size(char* resp);
/* grep the given size (in bytes) in resp after a pop3_list(sock,ID) request */
/* do not use after a pop3_list(sock,0) ! */

int stat2last(char* resp);
/* returns the last message's id on pop server */

int stat2bytes(char* resp);
/* returns the sumsize in bytes of all stored messages on server */
/* must only be called just after a pop3_stat() request */

char** uidl2array(char* resp);
/* WARNING: mus not be called after a mail deletion */
/* returns an array of unique strings for each message id */
/* array[0] gives array's last id */
/* must only be called just after a pop3_uidl(sock,0) request */

void freeuidlarray(char** arrray);
/* free the uidl array created by uidl2array */

char* uidli2sig(char* resp);
/* grep the pop signature of *one* message signature reply*/
/* should only be called on data received by a pop3_uidl(sock,ID) request */
/* do not use it after a pop3_uidl(sock,0) ! */



/***************************************************
 * high-level API for a SIMPLE MDA/MUA             *
 ***************************************************/

/******************************************************************************
 * This is the high-level API of libspopc and it is recommended to use it     
 * instead of the low-level one. This high-level API, in spite of its very    
 * 'teasing' name, just provides a *very simple* way to access and query a    
 * pop3 server with your e-mail client. This API handles pop3 in a very       
 * convenient manner for the non 'socket-aware' C developper.                 
 ******************************************************************************/

typedef enum{AUTHORIZATION,TRANSACTION,UPDATE}popstate;
/* pop server states definition from RFC 1725, not used here actually */

typedef struct{
        pop3sock_t sock;/* socket descriptor */
        struct sockaddr_in* connection;
        struct hostent* server;
        popstate state;/* pop server state */
        int* list;/* pop messages size list */
        char** uidl;/* pop messages signature list */
        int bytes;/* total stored (in bytes) on pop server */
        int last;/* last message id */
        int del;/* 0|1 flag to ask deletion of retrieved messages */
}popsession;

#define popbytes(s) ((s)->bytes)
/* gives the total stored data size (in bytes) on the pop server */
/* arg 's' is type 'popsession*'; 'result' is type 'int' */

#define popsetdel(s) ((s)->del=1)
/* asks the session to delete any retrieved messages on the server */
/* arg 's' is type 'popsession*' */

#define popsetundel(s) ((s)->del=0)
/* asks the session to not delete any retrieved message on the server */
/* arg 's' is type 'popsession*' */

#define popmsgsize(s,i) ((s)->list[(i)])
/* gives the size of message 'i' for session 's' */
/* args are type 'session*'(s) and 'int'(i) */
/* 'i' must *not* be 0 */

#define popmsguid(s,i) ((s)->uidl[(i)])
/* points to the 'char*' uid (unique signature) of 'int'(i) message id */

int poplast(popsession* session);
/* gives the id of the last message of the current session */

int popnum(popsession* session);
/* gives the current number of stored message. it is != to poplast() */

char* popbegin(const char* servername,const char* user, const char* pass, popsession** sp);
/* prepares, connect and get lists of messages stored on pop server */
/* you must give a valid servername, user and pass */
/* returns an error message if a problem occurs, else NULL */

char* popgethead(popsession* session, int id);
/* returns the header of a message (id between 1 and poplast()) or NULL if bad id */

char* popgetmsg(popsession* session, int id);
/* returns a message (id between 1 and poplast()) or NULL if bad id */

int popdelmsg(popsession* session, int id);
/* deletes message 'id' on pop server */
/* returns -1 if server error, 0 else */

int popcancel(popsession* session);
/* cancels all previous deletion on pop server */
/* returns -1 if server error, 0 else */

void popend(popsession* session);
/* quit and destroys pop session */

#ifdef __cplusplus
}
#endif
#endif