IMA2a4 2019/2020 EC1 : Différence entre versions

De Wiki d'activités IMA
(Travail effectué)
(Travail effectué)
Ligne 273 : Ligne 273 :
 
*2-Fonction Lect_Mail
 
*2-Fonction Lect_Mail
 
*3-Fonction Analyse arguments
 
*3-Fonction Analyse arguments
*4-Fonction Lockf
+
*4-Fonction Pose_verrou
 +
*5-Fonction Enleve_verrou
  
  
Ligne 409 : Ligne 410 :
 
*'''3)  Fonction Analyse Argument''' :
 
*'''3)  Fonction Analyse Argument''' :
  
La fonction Analyse argument permet de récupérer le chemin des messages
+
La fonction Analyse argument permet de donner le nom du répertoire racine des boites aux lettres par defaut c'est "/var/spool/mail"
 +
 
 +
elle est lancer dans le <code>main</code>
 +
 
 +
étant donné que le chemin sera le même pour tous les clients je recopie le contenu que la fonction renvoi à savoir le chemin des boites aux lettres
 +
 
 +
dans une variables globale nommée <code>chemin_spool</code>
 +
 
 +
si il n’y a pas d'argument alors le chemin par défaut sera "/var/spool/mail"
 +
 
 +
pour mes essai mes messages étant dans un autre répertoire alors j'utiliser la commande :
 +
 
 +
<code>"sudo ./station --spool ../Messages"</code>
 +
 
 +
 
 +
*'''4)  Fonction Pose_verrou''' :
 +
 
 +
La fonction Pose_verrou utilise la fonction lockf qui permet de poser un verrou sur un fichier pour évité que 2 clients ouvre le même fichier en même temps.
 +
 
 +
<code>int lockf(int fd, int cmd, 0);</code>
 +
 
 +
elle à besoin d'un file descriptor une commande(F_LOCK,F_ULOCK,F_TEST) pour verrouiller le fichier, le déverrouiller ou tester la présence de verrou.
 +
 
 +
je passe en argument a ma fonction le chemin du fichier a verrouiller.
 +
 
 +
Dans ma fonction je réalise un  <code>open</code>
  
 
== Documents ==
 
== Documents ==

Version du 30 août 2019 à 12:06

Présentation du projet

Contexte

La validation du semestre S8 dépend de la validation de cette épreuve complémentaire.

Objectif

Le but est de développer un système de messagerie personnelle très léger. Vous développerez plus particulièrement un serveur IMAP fonctionnant en IPv4 et en IPv6.

Description du projet

Vous développerez ce serveur IMAP sur le même modèle que le projet système réseau, en particulier concernant l'aspect structuré et multi-threadé.

Quelques directives spécifiques au serveur IMAP :

  • Pas de gestion de l'identification. Le serveur n'écoute que sur l'interface loopback. Donc seul un utilisateur ayant accès à la machine pourra utiliser le serveur IMAP. Pour un accès à distance, un tunnel créé par l'option -L de l'utilitaire ssh sera utilisé. Dans la phase d'identification du client IMAP seul le nom d'utilisateur sera exploité pour retrouver les messages. Le mot de passe sera lu sans effectuer de contrôle.
  • Vous utiliserez le même format de stockage des messages que celui décrit dans l'épreuve complémentaire dont le sujet est le développement d'un serveur SMTP. Les drapeaux des messages sont stockés dans le fichier d'extension .status en toutes lettres et un seul par ligne. Lors de la manipulation d'un message (ou de ses drapeaux) en lecture ou en écriture vous bloquerez les fichiers avec la fonction système lockf. Prévoyez une option -s ou --spool permettant de donner le nom du répertoire racine des boites aux lettres (/var/spool/mail par défaut).
  • Vous implanterez un serveur IMAP version 2 tel que défini par la RFC 1176. Vous implanterez en particulier les commandes NOP, LOGIN, LOGOUT, SELECT, CHECK, EXPUNGE, COPY, FETCH et STORE. Tenez-vous en aux 5 drapeaux systèmes.

Validation de l'épreuve

L'épreuve est validée si les sources sont lisibles et si le serveur supporte un test. Le test en question consistera à créer une arborescence de messages, à lancer le serveur IMAP et à vérifier avec l'application thunderbird si le serveur IMAP se comporte comme attendu par le client.

Matériel nécessaire

Aucun.

Planning prévisionnel

Travail effectué

SEMAINE 1 :


Durant la première semaine j'ai fait des recherches pour prendre en main le projet, comprendre le fonctionnement du protocole IMAP qui est un protocole qui permet d'accéder à ses courriers électroniques directement sur les serveurs.

  • J'ai cherché à comprendre la fonctionnement des fonctions NOP, LOGIN, LOGOUT, SELECT, CHECK, EXPUNGE, COPY, FETCH et STORE
  • Et aussi le fonctionnement des 5 drapeaux systèmes RECENT, SEEN, ANSWERED, FLAGGED, DELETED.
  • Ensuite, en reprenant et modifiant le serveur TCP qui a été crée pour le premier projet S&R. J'ai commencé à faire la réalisation du serveur IMAP2.

Le client se connecte et j'arrive a obtenir le TAG (A001,A002..) ainsi que la fonction (LOGIN, SELECT, FETCH...) et les arguments (ex: login mdp).

Il faut maintenant faire le traitement des information obtenu.

Pour la suite je vais commencer les fonctions "simples" du type LOGIN et LOGOUT.


SEMAINE 2 & 3 :


note : durant la semaine 2 et 3 j'ai eu des déplacements professionnels et personnels je n'ai pas pu beaucoup avancer le projet IMAP2..

Pendant cette période j'ai ajouté la fonction LOGIN et LOGOUT :

  • La fonction LOGIN : Pour la fonction LOGIN je suis parti du principe que le serveur a une base de données avec tous les utilisateurs,

pour vérifier si l'utilisateur existe bien dans la base de données j'ai créé un fichier LOGIN.txt qui contient tous les utilisateurs.

Lorsqu' un utilisateur met son identifiant pour se connecter, je vérifie qu'il soit bien dans la base de données (vérification du ficher LOGIN.txt) s'il existe je lui renvoi : "A001 OK User logged in"

sinon je renvoie un message d'erreur.

  • La fonction LOGOUT : Une fois l'utilisateur connecté il a accès aux fonctions NOOP, SELECT, CHECK, EXPUNGE, COPY, FETCH, STOREet enfin LOGOUT.

Tant qu'il ne se déconnecte pas avec la fonction LOGOUT , il reste connecté. Une fois qu'il se déconnecte je lui renvoie : "A007 OK Logout complete"

  • La fonction NOOP : Pour cette fonction, lorsque le client m'envoie un NOOP, je lui réponds un simple : "OK NOOP". il faudra que je rajoute le bon tag devant.
  • La fonction SELECT : Pour la fonction SELECT j'ai développé deux fonctions : Nombre_mail, Lect_Flags

La fonction Nombre_mail parcourt le répertoire de l'utilisateur connecte (passé en paramètre de la fonction) et elle retourne le nombre de mail dans son répertoire.

La fonction Lect_Flags permet de lire les flags dans chacun des .status de chaque message. Etant donné que les messages sont stockés sous la forme d'un fichier de nom numérique

représentant l'ordre de réception des messages, il m'a suffit de faire une boucle FOR qui s’incrémente et j'utilise l'incrémentation pour passer d'un .status à l'autre .

sprintf(Chemin,"../Messages/Utilisateur/%s/INBOX/%d.status",user,i);

le %s c'est l'utilisateur connecté et le %d l'incrément de la boucle FOR qui parcourt le nombre de mails passés en paramètres.

Pour la semaine 4 je vais continuer à optimiser les fonctions actuelles et développer la fonction CHECK.

SEMAINE 4 :


Durant la semaine 4 j'ai avancé sur plusieurs fonctions (version 4) :

  • 1-Modification de la fonction Lect_Flags pour renvoyer plusieurs paramètre .
  • 2-Fonction Sup_ligne qui permet de supprimer une ligne dans les fichiers .status .
  • 3-Amélioration de la fonction SELECT qui permet maintenant de supprimer les flags RECENT une fois la commande effectuée.
  • 4-Ajout de la fonction EXPUNGE.
  • 5-Ajout de la fonction CHECK .
  • 6-Vérification que le mot de passe soit différent d'un "string" vide.


  • 1) Fonction Lect_Flags :

Pour pouvoir "return" plusieurs variables et ne pas avoir à écrire une fonction par flag lu, j'ai ajouté un struct : nombre_flags

typedef struct{

int Recent;

int Deleted;

}nombre_flags;

Ainsi je peux renvoyer la structure.

return nombre_flag;


  • 2) Fonction Sup_ligne :

La fonction Sup_ligne permet de supprimer une ligne dans les les fichiers .status .

int Sup_Ligne(char * user,char * Flag, int num_mail)

Elle a besoin du nom de l'utilisateur connecté, le flag à supprimer ( RECENT, SEEN, ANSWERED, FLAGGED, DELETED) et le numéro du message à supprimer.

Son fonctionnement est assez simple, je recopie toutes les lignes dans un autre fichier temporaire sauf celle que je souhaite supprimer.

Ensuite je supprime le premier fichier avec la fonction remove

remove(Chemin)

Puis je renomme le fichier temporaire avec le même nom que le fichier initial

rename(Chemintemp,Chemin);


  • 3) Amélioration de la fonction SELECT :

Une fois la fonction SELECT exécutée il faut enlever les flags RECENT dans les .status . Or pour cela il faut se rappeler dans qu'elle .status il y a un flag RECENT

Pour faire cela, dans la fonction Lect_Flags je rajoute un tableau :

int *tab_sup dans ce tableau à chaque fois qu'on trouve le flag passé en paramètre dans un fichier .status je récupère le numéro du mail et je le stocke dans le tableau et j’incrémente.

Ainsi lorsque je veux supprimer tout les Flags correspondant il me suffit de parcourir le tableau et de lancer ma fonction int Sup_Ligne(char * user,char * Flag, int num_mail)

Avec int num_mail le numéro du mail à supprimer.

for (i=0;i<nombre_flag_t.Recent;i++)

{

Sup_Ligne(user,Flag,tab_sup[i]);

}

  • 4) Fonction EXPUNGE :

Pour la fonction EXPUNGE sur le même principe dans la fonction Lect_Flags je rajoute un tableau qui vérifie dans les .status les flag DELETED

et je stocke le numéro de mail dans un tableau.

for (i=0;i<nombre_flag_t.Deleted;i++) { sprintf(Chemin,"../Messages/Utilisateur/%s/INBOX/%d.status",user,tab_sup2[i]);

remove(Chemin);

sprintf(Chemin,"../Messages/Utilisateur/%s/INBOX/%d.txt",user,tab_sup2[i]);

remove(Chemin); }

Cela permet de suprimer les .status et les .txt


  • 5) Fonction CHECK :

La fonction CHECK reprend les mêmes éléments que la fonction SELECT


  • 6) Vérification du mdp :

Pour que l'utilisateur se connecte, il faut qu'il soit dans la base de données fichier LOGIN.txt et que sont mdp soit différent d'un "string" vide sinon il a un message d'erreur.


if ((login_ok==1) && (strcmp(arg2, "") != 0)


Pour la semaine 5 j'ai pour objectif de finir les 3 dernières fonctions COPY, FETCH et STORE .


SEMAINE 5 et 6 :


Durant la semaine 5 et 6 j'ai avancé sur les fonctions Store et Copy et amélioré le code (version 5) :

  • 1-Fonction Store
  • 2-Fonction ENUM_nb
  • 3-Fonction Copy
  • 4-Fonction Ajout ligne



  • 1) Fonction Store :

La fonction Store prend permet d'ajouter ou de supprimer un Flag des fichier .status

Pour faire cela le clients doit envoyer un message de ce type:

A001 STORE 5 (numéro du mail) +Flags (ou -Flags)\Deleted (ou \Flagged,\Answered...)

dans ma fonction je prend en compte le numéro du mail ensuite si le l’argument et de type +Flags(ajouter flags) ou -Flags(supprimer flags) et quelle type de flags il faut ajouter ou supprimer (\Flagged,\Answered...)

Ensuite j’appelle la fonction sup_ligne vu précédemment pour supprimer le flag correspondant.

ou Ajout_ligne que je détaillerez par la suite.



  • 2) Fonction ENUM_nb :

Pour les fonctions COPY et FETCH le client envoie un argument de type 1:5 pour dire qu'il veut soit copier soit fetch les mail(1,2,3,4,5)

La fonction Enum permet de recuperer l'argument 1:5 et d’énumérer dans un tableau tab_enum et d'avoir dans chaque case du tableau {"1","2","3","4","5"}

cela permet pour la fonction COPY et FETCH d'avoir le bon indice de fichier.


  • 3) Fonction Copy :

La fonction COPY se présente de cette façon:

A001 COPY 1:5 et INBOX2 (INBOX2 mailbox ou il faut copier les mail 1 à 5).

Comme le dit la RFC 1176 si la mailbox n'existe pas il faut la crée pour cela je vérifie si elle existe

if (stat(Chemin2_status, &st) == -1)

Ensuite dans une Boucle for je parcours le tableau tab_enum pour récupérer les numéros de mail a copié.


  • 4) Fonction Ajout ligne :

La Fonction ajout ligne permet d'ajouter un flags dans un .status

Ajt_Ligne(char *user, char *Flag, char *num_mail)

elle prend en argument le nom de l'utilisateur le Flags a copié et le numéro du mail a copié.


SEMAINE 7 :


Durant la semaine 7 j'avance sur les fonctions FETCH, Analyse arguments, et Lect_Mail pour lire les mail,ainsi que lockf (version 6) :


  • 1-Fonction FETCH
  • 2-Fonction Lect_Mail
  • 3-Fonction Analyse arguments
  • 4-Fonction Pose_verrou
  • 5-Fonction Enleve_verrou


  • 1) Fonction FETCH :


La fonction FETCH est la fonction principale du projet elle permet d'envoyer le contenu du mail au client en fonction de ce qu'il demande.

il y a en tout 9 choix possible pour les clients.


Le client peut sélectionner chacun des éléments ci-dessous

FLAGS // ALL // FAST

INTERNALDATE // ALL // FAST

RFC822.SIZE // ALL // FAST

ENVELOPE // ALL

RFC822.HEADER // RFC822

RFC822.TEXT // RFC822

s'il sélectionne ALL alors c'est équivalent a sélectionner les éléments ( FLAGS,INTERNALDATE,RFC822.SIZE,ENVELOPE)

s'il sélectionne FAST alors c'est équivalent a sélectionner les éléments ( FLAGS,INTERNALDATE,RFC822.SIZE)

s'il sélectionne RFC822 alors c'est équivalent a sélectionner les éléments (RFC822.HEADER,RFC822.TEXT)

Il peut tout les sélectionner indépendamment par exemple :

A001 FETCH 1:2 RFC822.SIZE

il aura alors la taille des mails 1 et 2.

Une fois que j'ai bien compris le fonctionnement j'ai déclarer une structure avec dedans les 6 int (les 3 autres "ALL,FAST,RFC822" étant seulement un composition des 6 élément a renvoyé)

typedef struct { int iEnvelope; int iFlags; int iRfc_header; int iRfc_text; int iRfc_size; int iInternaldate; } fetch_t;


Dans ma fonction Fetch je fais une vérification de l'argument si par exemple c'est ALL alors je mets a 1 les int iFlags,iInternaldate,iRfc_size,iEnvelope

et j'envoi ma structure a la fonction Lect_mail qui permet en fonction des int mis à 1 de renvoyé au client l’élément du mail correspondant.


  • 2) Fonction Lect_Mail :

la fonction Lect_Mail permet de renvoyé au client l’élément du mail en fonction de l'argument 2 de la commande FETCH.

Par exemple si la commande est :

A001 FETCH 1:3 RFC822

les int iRfc_header et iRfc_text seront égaux a 1

alors dans une boucle for qui énumère les messages 1 à 3

on renvoi le header du mail suivi de son contenu.



FLAGS (renvoi les flags contenu dans les .status)


On parcours le fichier .status correspondant au mail et on concatène le contenu du flags dans un char nommée flag_recu.



INTERNALDATE (renvoi la date du mail)

On récupère la date du mail avec la fonction stat qui renvoient des informations à propos d'un fichier

et on la concatène dans un char nommée internaldate.



RFC822.SIZE (renvoi la taille en nombres de caractère)

On fait une lecture du nombre de caractère du mail et on la concatène dans un char nommée rfc822_size.



ENVELOPE (on renvoi certains élément de l’entête du mail )

Pour récupérer uniquement le contenu de l’entête je vérifie dans chaque ligne du mail avec la fonction strstr si un élement qui caractérise l'entête

par exemple :"Date:", "Subject", "From:", "Sender:" sont des élément qui caractérise l’entête.

et si il y a un élément d’Entête on la concatène le contenu de la ligne du fichier dans un char nommée contenu_Envelope.


element_Envelope[9][MAX_LIGNE] = {"Date:", "Subject", "From:", "Sender:", "cc:", "In-Reply-To:", "Message-ID:", "Reply-To:", "To:"};


RFC822.HEADER (on renvoi les élément de l’entête du mail )

Même fonctionnement que ENVELOPE sauf qu'il y a plus d'élément qu'on vérifie

element_Header[14][MAX_LIGNE] = {"Date:", "Subject", "From:", "Sender:", "cc:", "In-Reply-To:", "Message-ID:", "Mail-From:", "ReSent-Date:", "ReSent-To:", "ReSent-To:", "ReSent-Message-ID:", "Reply-To:", "To:"};

on la concatène le contenu de la ligne du fichier dans un char nommée contenu_Header


RFC822.TEXT (on renvoi le contenu du mail )

Pour récupérer le contenu du mail sans l'entête je verifie toutes les lignes ou il n'y a pas d'entête et je les récupère.

on la concatène le contenu de la ligne du fichier dans un char nommée contenu_Texte


Ensuite on concatène tout les éléments en fonction des int mis a 1

puis on renvoie le contenu au client avec un fwrite.


  • 3) Fonction Analyse Argument :

La fonction Analyse argument permet de donner le nom du répertoire racine des boites aux lettres par defaut c'est "/var/spool/mail"

elle est lancer dans le main

étant donné que le chemin sera le même pour tous les clients je recopie le contenu que la fonction renvoi à savoir le chemin des boites aux lettres

dans une variables globale nommée chemin_spool

si il n’y a pas d'argument alors le chemin par défaut sera "/var/spool/mail"

pour mes essai mes messages étant dans un autre répertoire alors j'utiliser la commande :

"sudo ./station --spool ../Messages"


  • 4) Fonction Pose_verrou :

La fonction Pose_verrou utilise la fonction lockf qui permet de poser un verrou sur un fichier pour évité que 2 clients ouvre le même fichier en même temps.

int lockf(int fd, int cmd, 0);

elle à besoin d'un file descriptor une commande(F_LOCK,F_ULOCK,F_TEST) pour verrouiller le fichier, le déverrouiller ou tester la présence de verrou.

je passe en argument a ma fonction le chemin du fichier a verrouiller.

Dans ma fonction je réalise un open

Documents

Fichier:IMAP v1.zip

Fichier:IMAP v2.zip

Fichier:IMAP v3.zip

Fichier:IMAP v4.zip

Fichier:IMAP v5.zip

Fichier:IMAP v5 2.zip

Fichier:IMAP v6.zip Version du 28/08 manques encore des éléments..