/*
   Copyright (c) 1999 by MoGul <kaliph@gmx.net>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 dated June, 1991.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program;  if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
   
   Last changed: Jun 18. 1999
*/

#define DEBUG 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include "socklib.h"

#define TYPE_POP 1
#define TYPE_IMAP 2

#define ACK_MSG "+OK"
#define ERR_MSG "+ERR"
#define IMAP_ACK_MSG "* OK"

#define TIMEOUT 120
#define DEFAULTPORT 110
#define DEFAULTIMAPPORT 143

/* Macro... for lazy programmers ;) */
#define WAITOK {					\
    switch (Sread(sd, input, 200, TIMEOUT)) {		\
        case -1:	/* Error */			\
        case 0:		/* Timeout */			\
           return -1;					\
    }							\
    sscanf(input, "%5s", strg);				\
    if (strcmp(strg, ACK_MSG) != 0)			\
       return -1;					\
}

int poptype(char *mailboxname)
{
   if (mailboxname[0] == ':' && mailboxname[1] == ':')
      return TYPE_POP;
   if (mailboxname[0] == '>' && mailboxname[1] == '>')
      return TYPE_IMAP;
   return 0;
}

int imap(int sd, int *nm, int *om, char *user, char *password)
{
   char input[200], output[200], strg[10];
   char *pnt;
   
   if (Sread(sd, input, 200, TIMEOUT) <= 0)
      return -1;

   sscanf(input, "%8s", strg);
   if (strncmp(input, IMAP_ACK_MSG, 4) != 0)
      return -1;
   
   sprintf(output, "A000 LOGIN %s %s\n", user, password);
   Swrite(sd, output);
   if (Sread(sd, input, 200, TIMEOUT) <= 0)
      return -1;

   sscanf(input, "%8s", strg);
   if (strncmp(input, "A000 OK", 7)) {
      /* LOGIN failed. Logout and quit. */
      if (DEBUG) fprintf(stderr, "Username and password were not accepted.\n");
      sprintf(output, "A001 LOGOUT\n");
      Swrite(sd, output);
      return -1;
   }
   
   sprintf(output, "A001 SELECT INBOX\n");
   Swrite(sd, output);

   do {
      if (Sread(sd, input, 200, TIMEOUT) <= 0)
         return -1;

      if (strstr(input, "EXISTS"))
         *nm = atoi(strstr(input, "*") + 1);
   } while (strncmp(input, "A001 OK", 7));
   
   sprintf(output, "A002 CHECK\n");
   Swrite(sd, output);
   if (Sread(sd, input, 200, TIMEOUT) <= 0)
      return -1;
   if (strncmp(input, "A002 OK", 7)) {
      if (DEBUG) fprintf(stderr, "That jerk doesn't know CHECK!\n");
      sprintf(output, "A003 LOGOUT\n");
      Swrite(sd, output);
      return -1;
   }
   
   sprintf(output, "A003 SEARCH UNSEEN\n");
   Swrite(sd, output);
   if (Sread(sd, input, 200, TIMEOUT) <= 0)
      return -1;
   
   /* We got "* SEARCH X X X" - count the spaces and get the amount */
   pnt = &input[7];
   *nm = 0;
   while (*pnt != '\0') {
      if (*pnt == ' ') (*nm)++;
      pnt++;
   }
   
   if (Sread(sd, input, 200, TIMEOUT) <= 0)
      return -1;
   if (strncmp(input, "A003 OK", 7))
      if (DEBUG) fprintf(stderr, "WARNING: SEARCH UNSEEN did not terminate with OK\n");

   sprintf(output, "A004 LOGOUT\n");
   Swrite(sd, output);
   Sread(sd, input, 200, TIMEOUT);
   return 0;
}

int pop3(int sd, int *nm, int *om, char *user, char *password)
{
    char input[200], output[200], strg[5];
    char *pnt;
    int i;
    
    /* We have connected, now we want to see a "+OK" */
    WAITOK;
    
    /* Server gently said hello. Now pass username and Password */
    sprintf(output, "USER %s\n", user);
    Swrite(sd, output);
    WAITOK;
        
    sprintf(output, "PASS %s\n", password);
    Swrite(sd, output);
    WAITOK;
    
    Swrite(sd, "STAT\n");
    WAITOK;
    pnt = input + strlen(strg) + 1;
    i = sscanf(pnt, "%d", nm);
    
    /* Not all pop-servers support this command, so we have to trap this */

    Swrite(sd, "LAST\n");

    switch (Sread(sd, input, 200, TIMEOUT)) {
        case -1:	/* Error */
        case 0:		/* Timeout */
            return -1;
    }
    sscanf(input, "%5s", strg);
    if (strcmp(strg, ACK_MSG) == 0) {
    /* LIST works */
        pnt = input + strlen(strg) + 1;
        i = sscanf(pnt, "%d", om);
    } else *om = 0;
    
    /* We've got it. Now let's go. */
    Swrite(sd, "QUIT\n");
    WAITOK;
    return 0;
}

int pop(char *string, int *nmail, int *oldmail)
/* String must contain - in this order:
    servername username password [port#] 
    
    nmail: total number of available mail
    oldmail: number of old mail			*/

{
    SOCKET *sock;
    int sd, i, port = 0, type;
    char server[100], user[100], password[100];
    char *pnt;
    static int InDuty = 0;

    if ((type = poptype(string)) == 0)
       return -1;
       
    if (InDuty)
        return -1;
    InDuty = 1;

    pnt = string + 2;
    if (sscanf(pnt, "%100s", server) != 1) {
        InDuty = 0;
        return -1;
    }
    
    pnt += strlen(server) + 1;
    if (sscanf(pnt, "%100s", user) != 1) {
        InDuty = 0;
        return -1;
    }
    
    pnt += strlen(user) + 1;
    if (sscanf(pnt, "%100s", password) != 1) {
        InDuty = 0;
        return -1;
    }
    
    pnt += strlen(password) + 1;
    if (sscanf(pnt, "%d", &port) != 1)
       switch (type) {
          case TYPE_POP: port = DEFAULTPORT; break;
          case TYPE_IMAP: port = DEFAULTIMAPPORT; break;
       }

    /* Create socket */
    if (!(sock = Sopen())) {
        InDuty = 0;
        return -1;
    }

    /* Connect to server */
    if ((sd = Sclient(sock, server, port)) == -1) {
        InDuty = 0;
        return -1;
    }
    
    /* POP 3 or IMAP mailbox? */
    switch (type) {
       case TYPE_POP: if (pop3(sd, nmail, oldmail, user, password) == -1) {
          		if (DEBUG) fprintf(stderr, "POP3 connection failed\n");
                        InDuty = 0;
                        return -1;
                      }
                      break;
       case TYPE_IMAP: if (imap(sd, nmail, oldmail, user, password) == -1) {
          		if (DEBUG) fprintf(stderr, "IMAP connection failed\n");
                        InDuty = 0;
                        return -1;
                      }
                      break;
    }
    
    Sclose(sock);

    InDuty = 0;
    return *nmail;
}
