/*
 *  Copyright (c) 2008, Rodrigo OSORIO (ros)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of  nor the names of its contributors may be used to
 *    endorse or promote products derived from this software without specific
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#define STDIN   0
#include <sys/termios.h>


#include <stdio.h>    
#include <netinet/in.h>
#include <sys/socket.h> 
#include <sys/types.h>
#include <arpa/inet.h> 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>

//#define DEBUG

int net_send(int sock,char * buffer)
{
  int btosend = 0;

  btosend = strlen(buffer);
#ifdef DEBUG
  fprintf(stderr,">> %s\n",buffer);
  fflush(stderr);
#endif
  return  send(sock,buffer,btosend,0)!= btosend ? 1:0;
}

int net_recv(int sock,char * buffer,int len)
{
  int curr_recv = 0;
  int done  = 0;
  int problem = 0;
  unsigned char lastcar;
  
  while(!done)
  {
    if(recv(sock,&lastcar,1,0)== 0)
      problem = 1;
    else
    {
      switch(lastcar)
      {
      	case  10:
	break;

	case 13:
	  done = 1;
	break;

	default:
          if((curr_recv+1)< len)
	  {
	    buffer[curr_recv++] = lastcar;
	  }
	  else
	    problem = 2;
       break;
      }
    }
  }
#ifdef DEBUG
  fprintf(stderr,"<< %s\n",buffer);
  fflush(stderr);
#endif
  if(!problem)
  {
     buffer[curr_recv] = 0;
     return 0;
  }
  
  return 1;
}

int pop_is_err(char * buffer)
{
  return strncmp(buffer,"-ERR",3) == 0?1:0;
}

int pop_is_ok(char * buffer)
{
  return strncmp(buffer,"+OK",3) == 0?1:0;
}
  
int pop_is_eol(char * buffer)
{
  return strcmp(buffer,".") == 0?1:0;
}
  
int printMsg(int sock,int msg_id)
{
  int i = 0;
  int done    = 0, // Not done
  problem = 0; // No problem
  char recv_buffer[1024];

  while(!done && !problem)
  {
    switch (++i)
    {
      case 1:
        sprintf(recv_buffer,"top %d 0\n",msg_id);
        problem = net_send(sock,recv_buffer);
      break;
    
      case 2:
        problem = net_recv(sock,recv_buffer,1024);
        if(!problem)
          problem = pop_is_err(recv_buffer);
	  printf("-----------------------------------------------------\n");
      break;

      case 3:
        problem = net_recv(sock,recv_buffer,1024);
        if(!problem)
          if(!pop_is_eol(recv_buffer))
	  {
	    if( (strncmp(recv_buffer,"Date",4) == 0) ||
	        (strncmp(recv_buffer,"From",4) == 0) ||
	        (strncmp(recv_buffer,"Subject",7) == 0))
		printf("M%02d : %s\n",msg_id,recv_buffer);
	    
            i--;
	  }
      break;
     
      case 4:
        done = 1;
      break;
    }
  }
  return problem;
}

void read_account_settings(char * conf,char * username,char * hostname)
{
  char accoun_file[1024];
  FILE * account;
  sprintf(accoun_file,"%s/.checkmail/%s.acc",getenv("HOME"),conf);

  account = fopen(accoun_file,"rt");
  if(account != NULL)
  {
     fscanf(account,"%s %s",username,hostname);
  }
  else
  {
   printf("Account not found\n");
   exit(0);  
  }
}


int  main(int argc,char ** argv)
{
  char has_mail = 0;
  struct  termios  u235;
  char    nsa[82];
  int sock;                        
  struct sockaddr_in echoServAddr; 
  struct hostent * pent;
  int i = 0,
      j = 0;
  int done    = 0, // Not done
      problem = 0; // No problem
  char recv_buffer[1024];
  char params_file[50];
  char user[256];
  char poper[256];
  char conf[50] = "default";
  int len = 0;
  int array[999];
  FILE * fparams;
  FILE * fpass;
  int lastmessage;
  int reset_message_list = 0;
  ioctl(STDIN, TIOCGETA, &u235);

  u235.c_lflag &= ~ECHO;
  ioctl(STDIN, TIOCSETA, &u235);

  printf("Checkmail by rodrigo osorio\n (c) %s\n=======================\n",__DATE__);

  if(argc > 1)
  {
    if(strcmp(argv[1],"-r")==0)
    {
      lastmessage = 0;
      reset_message_list = 1;            
      if(argc > 2)
	 strcpy(conf,argv[2]);
    }
    else
    {
     strcpy(conf,argv[1]);
    }

  }

  read_account_settings(conf,user,poper);

  sprintf(params_file,"%s/.checkmail/%s_%s.chk",getenv("HOME"),user,poper);
  if(!reset_message_list)
  {
    fparams = fopen(params_file,"rb");
    if(fparams != NULL)
    {
      fread((char *)&lastmessage,sizeof(int),1,fparams);
      fclose(fparams);
    }  
    else lastmessage = 0;
  }


  sprintf(recv_buffer,"%s/.checkmail/pass",getenv("HOME"));
  fpass = fopen(recv_buffer,"rb");
  if(fpass == NULL)
  {
    printf("Enter password:\n");
    scanf("%s",nsa);
    //read(STDIN, nsa, sizeof nsa - 1);

    j = strlen(nsa);
    nsa[j] = 0;
    u235.c_lflag |= ECHO;
    ioctl(STDIN, TIOCSETA, &u235);
  }
  else
  {
        j = 0;
  	while(fread((char *)&nsa[j++],1,1,fpass) > 0);
	nsa[j-1] = 0;

	fclose(fpass);
  }


  if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  {
    return 1;
  }

  /* Construct the server address structure */
  memset(&echoServAddr, 0, sizeof(echoServAddr));           /* Zero out structure */
  echoServAddr.sin_family      = AF_INET;                   /* Internet address family */
  //echoServAddr.sin_addr.s_addr = inet_addr("212.27.48.3"); /* Server IP address */

  pent = gethostbyname(poper);
  if(pent == NULL)
  {
    printf("Host not found\n");
    exit(0);
  }
  
  bcopy((void *)pent->h_addr_list[0],(void *)&echoServAddr.sin_addr, pent->h_length);
  

  echoServAddr.sin_port        = htons(110);                /* Server port */
  

  printf("\r                              \r%s","connexion en cours....");
  fflush(stdout);

  /* Establish the connection to the echo server */
  if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
  {
    return 1;
  }

  while(!done && !problem)
  {
    switch(++i)
    {
      case 1:
       //Wait for the OK
       //************************
          problem = net_recv(sock,recv_buffer,1024);
          if(!problem)
          {
            if(!pop_is_ok(recv_buffer))
            {
              problem = pop_is_err(recv_buffer);
              i--;
            }
          }
      break;

      case 2:
        printf("\r                              \r%s","autentification....");
        fflush(stdout);
        problem = net_send(sock,"USER ");
        if(!problem) problem = net_send(sock,user);
        if(!problem) problem = net_send(sock,"\n");
      break;

      case 3:
        problem = net_recv(sock,recv_buffer,1024);
        if(!problem)
          problem = pop_is_err(recv_buffer);
      break;

      case 4:
        
        problem = net_send(sock,"PASS ");
        problem = net_send(sock,nsa);
        problem = net_send(sock,"\n");

      break;

      case 5:
        problem = net_recv(sock,recv_buffer,1024);
        if(!problem)
          problem = pop_is_err(recv_buffer);
      break;

      case 6:
        printf("\r                              \r%s\n","recuperation des messages....");
	fflush(stdout);
        problem = net_send(sock,"list\n");
      break;
      
      case 7:
        problem = net_recv(sock,recv_buffer,1024);
        if(!problem)
          problem = pop_is_err(recv_buffer);
        len = 0;
      break;
      
      case 8:
        problem = net_recv(sock,recv_buffer,1024);
        if(!problem)
          if(!pop_is_eol(recv_buffer))
	  {
            sscanf(recv_buffer,"%d ",&j);
	    array[len] = j;
            len++; 
            --i;
	  }
          j = 0;
      break;

      case 9:
        if(j<len)
        {
          if(j >= lastmessage)
	  {
            problem = printMsg(sock,array[j]);
            lastmessage++;
            has_mail = 1;
          }
          j++;
          i--;
	}
      break;
      
      case 10:
        fparams = fopen(params_file,"wb");
        if(fparams != NULL)
        {
          fwrite((char *)&lastmessage,sizeof(int),1,fparams);
          fclose(fparams);
        }  
        if(!has_mail) printf("no mail.\n");
        printf("bye!\n");
        net_send(sock,"quit\n");
	done = 1;
      break;
    }
  }
  if(problem)
     printf("Problem dectected on %d\n",i);

  close(sock);
  
}


