POPuX, un petit client pop qui connect a un serveur pop et affiche combien de mail l'user en a dans sa boite et télécharge le contenu des maild dans un fichier popux-mail.
POPux est un petit fetch mail a l'exception qu'il ne supprime pas d'email ,vous pouvez donc le testez sans risque de perdre vous mail a jamais.
Vous pouvez utilisez POPuX comme une framework pour developer vous propre client car il n'est pas complet puisque il n'ya pas d'allocage dynamique de la taille des mails, donc si un mail est superieur a celui du buffer de POPuX le resultat est le crash du programme avec un(EXIT_FAILURE) comme code d'erreur.
Le travail d'origine est un petit tutorial sur les winsock (donc windows) qui s'appelle popclt que vous pouvez trouvez ici:
http://www.exegesis.uklinux.net/gandalf/winsock/winsock2.htm
j'ai donc porter le code vers *nix .
Source / Exemple :
// cc popuxc.c-o POPuX
/***************************************************************************
- Copyright (C) 2006 by James Mrad *
- xtremejames183@msn.com *
- *
- 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; either version 2 of the License, or *
- (at your option) any later version. *
- *
- 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., *
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
/*
- un petit WARNING
- Testez le client sur un vrai serveur pop dont vous n'avez pas le droit de vous connecter
- ou vous n'avez pas la permission releve de l'illegal.
- Vous pouvez le tester chez vous si vous avez une
- linux box et un petit network avec un serveur POP ,tranquillement sans aucun risque de represaille.
- L'AUTEUR N'ASSUME AUCUNE RESPONSABLITE SUR UNE UTILISATION MAILVEILLANTE OU ILLEGALES DU CODE.
- /
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netdb.h>
//taille maximum d'un mail
#define BUF_SIZE 650000
// pop port
#define POP_PORT 110
//message d'erreur du serveur
#define ERR_MSG "-ERR"
//log
char * FILE_BUF;
//buffer d'enregistrement
char * REC_BUF;
void sigchld_handler(int a)
{
while(waitpid(-1,NULL,WNOHANG)>0);
}
// gestion d'erreur preovenant du serveur
void pop_msg_err();
//log msg
void write_log(int file_type, char *msg);
//gestion des erreurs
char * p_error(char *err,int id);
//fonction pour retirer vous mail du serveur
int retreive(int start,int end,int *sock);
int main(int argc, char *argv[])
{
int sock; //descripteur socket
struct sockaddr_in addr; //adresse
struct hostent * host; //hote
int err; //erreur socket
char hostname[20]; //information sur le serveur
char login[20]; //votre compte
char password[20]; //votre pass
int i,j; //compteur generale
char tempbuf[20]=""; //chaine temporaire pour le parsing
int num_flag=0; //un ptit flag
time_t time_now; //de time.h
/* allocage dynmaique de la mermoire du heap
calloc au lieu de malloc*/
FILE_BUF=calloc(BUF_SIZE,sizeof(char)+1);
REC_BUF=calloc(BUF_SIZE,sizeof(char)+1);
//get time
time(&time_now);
sprintf(FILE_BUF,"POPuX started on: %.24s\n",ctime(&time_now));
write_log(1/*log file */|4/*ecran*/,FILE_BUF);
// creer une socket en mode TCP/IP
if(( sock=socket(PF_INET,SOCK_STREAM,0))<0)
write_log(1/*log file*/|4,p_error("Socket\n",0));
bzero( (char *)&addr,sizeof addr);
addr.sin_family = AF_INET; //internet
addr.sin_port = htons(POP_PORT); //pop port
printf("Enter Hostname e.g(pop.myhostname.com): ");
/* comme vous savez scanf()
n'est pas la meilleur fonction que
C offre.Pour un vrai client je prefere de loin
fgets(hostname,sizeof(hostname),stdin);
mais c'est pas notre vrai probleme.
scanf("%s",hostname);
printf("Login : ");
scanf("%s",login);
printf("Password: ");
scanf("%s",password);
sprintf(FILE_BUF,"Connecting to %s using username: %s\n",hostname,login);
write_log(1/*log file*/,FILE_BUF);
//DNS
if( (host=gethostbyname(hostname) )==NULL)
write_log(1/*log file*/|4,p_error("DNS error\n",1));
//addresse IP du serveur
addr.sin_addr.s_addr=*((unsigned long *)host->h_addr);
//mode connection
if((err=connect(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr)))<0)
write_log(1/*log file*/|4,p_error("Connect\n",0));
sprintf(FILE_BUF,"Connected to %s on %s\n",inet_ntoa(*((struct in_addr *)host->h_addr)),ctime(&time_now));
write_log(1/*log file*/|4,FILE_BUF);
if((err=recv(sock,REC_BUF,BUF_SIZE,0))<0)
/*normallement si tous ce passe bien
vous devez recevoir +OK
sinon -ERR en cas d'echec
write_log(1/*log file*/|4/*stdout:screen*/,p_error("Recv\n",0));
sprintf(FILE_BUF,"received: %s\n",REC_BUF);
//ecrire sur le fichier popux.log
write_log(1/*log file*/|4,FILE_BUF);
if(strstr(REC_BUF,ERR_MSG)!=NULL) //chercher si ilya la chaine -ERR dans le buffer d'enregistrement
pop_msg_err();
strcpy(REC_BUF,"USER ");
strcat(REC_BUF,login); //envoyer votre login
strcat(REC_BUF,"\r\n");
if((err=send(sock,REC_BUF,strlen(REC_BUF),0))<0)
write_log(1/*log file*/|4/*stdout:screen*/,p_error("Send\n",0));
sprintf(FILE_BUF,"send: %s",REC_BUF);
write_log(1/*log file*/,FILE_BUF);
if((err=recv(sock,REC_BUF,BUF_SIZE,0))<0) //retourne en cas de succes +OK
write_log(1/*log file*/|4/*stdout:screen*/,p_error("Recv\n",0));
sprintf(FILE_BUF,"received: %s\n",REC_BUF);
write_log(1/*log file*/|4/*stdout:screen*/,FILE_BUF);
if(strstr(REC_BUF,ERR_MSG)!=NULL)
pop_msg_err();
strcpy(REC_BUF,"PASS ");
strcat(REC_BUF, password); //envoyer votre pass super secret
strcat(REC_BUF, "\r\n");
if((err=send(sock,REC_BUF,strlen(REC_BUF),0))<0)
write_log(1/*log file*/|4/*stdout:screen*/,p_error("Send \n",0));
sprintf(FILE_BUF,"send: %s",REC_BUF);
write_log(1/*log file*/,FILE_BUF);
if((err=recv(sock,REC_BUF,BUF_SIZE,0))<0)
write_log(1/*log file*/|4/*stdout:screen*/,p_error("Recv \n",0));
sprintf(FILE_BUF,"received: %s\n",REC_BUF); //retourne en cas de succes +OK
write_log(1/*log file*/|4/*stdout:screen*/,FILE_BUF);
if(strstr(REC_BUF,ERR_MSG)!=NULL) //recherche d'eventuel erreur serveur
pop_msg_err();
strcpy(REC_BUF,"STAT\r\n"); //envoyer la commande STAT
if((err=send(sock,REC_BUF,strlen(REC_BUF),0)<0))
write_log(1/*log file*/|4/*stdout:screen*/,p_error("Send \n",0));
sprintf(FILE_BUF,"Send %s\n",REC_BUF);
write_log(1,FILE_BUF);
if((err=recv(sock,REC_BUF,strlen(REC_BUF),0))<0)
write_log(1/*log file*/|4/*stdout:screen*/,p_error("Recv \n",0));
sprintf(FILE_BUF,"received: %s\n",REC_BUF);
write_log(1,FILE_BUF);
if(strstr(REC_BUF,ERR_MSG)!=NULL)
pop_msg_err();
/* les choses serieuse commence
- vous recevrez normallement +OK X Y ou X est le nombre de mail que vous avez
- et Y leur taille en octets. NB: le buffer qu'on a allouer
- ne serais pas suffisant pour un vrai client pop .
- il devrez etre dynamiquement allouez apres avoir
- determiner la taille de vos mail en attente
- /
i=j=0;
//combien de mail on a
while(i) {
if( REC_BUF[i]> '0' && REC_BUF[i] )
{
while( REC_BUF[i] != ' ') {
tempbuf[j]=REC_BUF[i];
j++;
i++;
}
num_flag=1;
tempbuf[j]='\0';
}
i++;
}
i=atoi(tempbuf); //nombre d'email
printf("There are %d waiting for you\nRetreive messages Now(Y/N) ",i);
char c=getchar();
while(c!='n'&&c=='y')
{
if(!retreive(j,i,&sock))
printf("Everything Done..Open mail-popux to view received mail.\n");
else
printf("An error Occured See popux.log for details\n");
c='n';
}
// faire le nettoyage et quitter
strcpy(REC_BUF,"QUIT\r\n");
if(err=send(sock,REC_BUF,strlen(REC_BUF),0)<0)
write_log(1|4,p_error("Send\n",0));
sprintf(FILE_BUF,"Send %s\n",REC_BUF);
write_log(1,FILE_BUF);
printf("Cleaning...\n");
free(FILE_BUF);
free(REC_BUF);
#ifdef WIN32
WSACleanup();
getch();
#endif
return EXIT_SUCCESS;
}
void pop_msg_err()
{
printf("POPuX: The POP sever returned an error msg Check popux.log for details\n");
#ifdef WIN32
WSACleanUp();
getch();
#endif
exit(EXIT_SUCCESS);
}
//log msg
void write_log(int file_type, char *msg)
{
const int to_log=1;
const int to_mail=2;
const int to_printf=4;
if ( (file_type & to_log)!=0 )
{
FILE *fp=fopen("popux.log","a+");
if(!fp) {
perror("POPuX\n");
exit(EXIT_FAILURE);
}
fprintf(fp,"%s\n",msg);
fclose(fp);
}
if( (file_type & to_mail) !=0)
{
FILE *fp=fopen("mail-popux","a+");
if(!fp) {
perror("POPuX\n");
exit(EXIT_FAILURE);
}
fprintf(fp,"%s\n",msg);
fclose(fp);
}
if( (file_type & to_printf) !=0)
{
printf("%s\n",msg);
}
}
char * p_error(char *err,int id)
{
// gestion d'erreur
if(!id)//id==0
perror(err);
else
herror(err); //pour les erreurs DNS
return err;
}
//Fetcher vos mails
int retreive(int start,int end,int *sock)
{
const int TO_MAIL=2;
/* LE VRAI PROBLEME
- A ce point on devrez OBTENIR la taille de chaque email en attente
- sur le serveur POP et allocer dynamiquement de la mémoire, ou essayer
- de synchronizer l'acces.
- Jusqu'a ici, laissons le code simple. Si vous
- avez un email supperieur a celui du buffer(BUF_SIZE), vous assistez a un joli
- crash du programme!
- /
for(start=1;start<=end;start++)
{
sprintf(REC_BUF,"RETR %d\r\n",start);
printf("Retreiving msg number %d\n",start);
if(send(*sock,REC_BUF,strlen(REC_BUF),0)<0) //envoyer la commande RETR au serveur
{
write_log(1/*log file*/|4,p_error("Send\n",0));
return -1; //error code
}
sprintf(FILE_BUF,"Sent %s\n",REC_BUF);
write_log(1,FILE_BUF);
if(recv(*sock,REC_BUF,BUF_SIZE,0)<0); //+OK en cas de succes
{
write_log(1/*log file*/|4,p_error("Recv\n",0));
return -1; //error code
}
sprintf(FILE_BUF,"received: %s ",REC_BUF);
write_log(1,FILE_BUF);
if(strstr(REC_BUF,ERR_MSG)!=NULL) // ou cas une erreur c'est produite
pop_msg_err();
if(recv(*sock,REC_BUF,BUF_SIZE,0)<0) // enfin on retire le mail
{
write_log(1|4,p_error("recv\n",0));
return -1;
}
sprintf(FILE_BUF,"%s\n",REC_BUF);
write_log(TO_MAIL/*ecrire le mail sur le fichier Mail-popux*/,FILE_BUF);
}
return 0; //fin
}
Conclusion :
Voila j'attends vos critique,commentaire... surtout sur l'allocage dynamique de la taille des messagess.
Dans le zip vous trouver le code mais les commentaires sont en anglais car je dois poster sur planet-code.
A+.
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.