#include #include #include #include #include #include #include #include #include #include #include "serv.h" /* à compiler avec : gcc -I`pg_config --includedir` -L`pg_config --libdir` -lpq base.c server.c */ int numero = 0; char * fichier (char * id, char * numero) { char * res; asprintf (&res, "%s/%s.%s", SPOOLPATH, id, numero); return res; } PGconn * connecter () { return PQconnectdb (PQCONN); } void deconnecter (PGconn* c) { PQfinish (c); free (c); } PGresult * executer (char* requete) { PGconn* c = connecter (); PGresult * res = PQexec (c, requete); deconnecter (c); return res; } char * escape (char* ch) { int n = strlen (ch); char *res = malloc (sizeof (char[2*n + 1])); PQescapeString (res, ch, n); return res; } char * lire_fichier (char * fichier, int * taille) { char *buff = malloc (1); FILE *fich = fopen (fichier, "r"); int pos = 0; int lus = 0; while (!(feof (fich))) { realloc (buff, pos + 1024); lus = fread (&buff[pos], 1, 1023, fich); pos += lus; } *taille = pos; buff[pos] = 0; fclose (fich); return buff; } char * lire_message_par_id (char* id, int * taille) { char *requete; asprintf (&requete, \ "select numero_fichier from messages where id = '%s';", \ id); printf ("%s\n", requete); PGresult * res = executer (requete); free (requete); if (0 == PQntuples (res)) return NULL; char * fich = fichier (id, PQgetvalue(res, 0, 0)); char * resultat = lire_fichier (fich, taille); free (fich); return resultat; } char * message_id (char * conti, char * numero) { char *requete; char *resultat; asprintf (&requete, \ "select message from messages_contis where conti = '%s' and numero = %s;", \ conti, numero); printf ("%s\n", requete); PGresult * res = executer (requete); free (requete); if (0 != PQntuples (res)) resultat = PQgetvalue (res, 0, 0); return resultat; } char * lire_conti (char * conti) { char *requete; asprintf (&requete, \ "select numero,message from messages_contis where conti = '%s' order by numero;", \ conti); printf ("%s\n", requete); PGresult * res = executer (requete); free (requete); int n = PQntuples (res); if (0 == n) return NULL; char * ret = malloc (1); *ret = 0; char * ret2; int i; for (i = 0; i < n; i++) { asprintf (&ret2, "%s%s:%s\n", \ ret, PQgetvalue (res, i, 0), PQgetvalue (res, i, 1)); free (ret); ret = ret2; } return ret; } char * lister_contis () { PGresult * res = executer ("select nom from contis;"); int n = PQntuples (res); if (0 == n) return NULL; char * ret = malloc (1); ret[0] = 0; char * ret2; int i; for (i = 0; i < n; i++) { asprintf (&ret2, "%s%s\n", ret, PQgetvalue (res, i, 0)); free (ret); ret = ret2; } return ret; } char * creer_id (time_t date) { char *id; asprintf (&id, "%.8x%.8x", date, random ()); return id; } void creer_message (struct msg * msg) { int i; /* génération du message id */ srandom (msg->date); char * id = creer_id (msg->date); printf ("Création du message %s\n", id); char* sender = msg->sender; char* from = escape (msg->from); char* subject = escape (msg->subject); char * fichier_corps = fichier (id, "0"); char * date = ctime (&(msg->date)); date[24] = 0; char * req1 = malloc (1); req1[0] = 0; char * req15; char * req9; char * body1 = malloc (13); strcpy (body1, "REFERENCES: "); char * body15; PGresult * resref; int nbref_eff = 0; if (msg->nrefs > 0) { for (i = 0; i < msg->nrefs; i++) { asprintf (&req9, "select * from messages where id = '%s';", \ msg->refs[i]); resref = executer (req9); free (req9); if (0 < PQntuples(resref)) { nbref_eff++; asprintf (&body15, "%s%s, ", body1, msg->refs[i]); free (body1); body1 = body15; asprintf (&req15, \ "%s insert into refs(de, a) values('%s','%s') ;", \ req1, id, msg->refs[i]); free (req1); req1 = req15; } else { printf("Référence à un message inexistant : '%s'\n", \ msg->refs[i]); } } if (nbref_eff != 0) body1[strlen (body1) - 2] = 0; char * pere = msg->refs[msg->nrefs - 1]; asprintf (&req15, \ "%s %s values ('%s', '%s', '%s', '%s', '%s', '%s'); %s (%s '%s') || '%s, ' %s '%s' ; %s;", \ req1, \ "insert into messages(id, date, sender, \"from\", subject, pere)", \ id, date, sender, from, subject, pere, \ "update messages set fils = ", \ "select fils from messages where id = ", pere, \ id, \ "where id = ", pere, \ "lock contis in row exclusive mode"); free (req1); free (pere); req1 = req15; } else { asprintf (&req1, \ "%s values ('%s', '%s', '%s', '%s', '%s'); %s;", \ "insert into messages(id, date, sender, \"from\", subject) ", \ id, date, sender, from, subject, \ "lock contis in row exclusive mode"); }; PGresult * resconti; int nb_effectif = 0; char * body2 = malloc (13); strcpy (body2, "NEWSGROUPS: "); char * body25; for (i = 0; i < msg->nngrp ; i++) { char * conti = msg->newsgrps[i]; asprintf (&req9, \ "select lecture_seule from contis where nom = '%s';", \ conti); resconti = executer (req9); free (req9); if (0 < PQntuples (resconti) && \ 0 != strcmp ("t", PQgetvalue (resconti,0,0))) { nb_effectif++; asprintf (&body25, "%s%s, " , body2, conti); free (body2); body2 = body25; asprintf (&req15, \ "%s %s ('%s', '%s', (%s '%s')); %s %s '%s';" , \ req1, \ "insert into messages_contis (message, conti, numero) values", \ id, conti, \ "select prochain_numero from contis where nom = ", conti, \ "update contis set prochain_numero = 1 + prochain_numero", \ "where nom = ", conti); free (req1); req1 = req15; printf ("%s\n", req1); } else { printf ("Le conti '%s' n'existe pas ou est en lecture seule.\n", \ conti); } } if (nb_effectif != 0) { /* effacer la dernière virgule */ body2[strlen (body2) - 2] = 0; } /* génération du corps complet */ char * body; asprintf (&body, "%s\nFROM: %s\nSENDER: %s\nSUBJECT: %s\n%s\n\n%s", \ body2, msg->from, msg->sender, msg->subject, body1, msg->body); free (body1); free (body2); free (from); free (sender); free (subject); if (nb_effectif != 0) { /* écriture du fichier */ FILE * fich = fopen (fichier_corps, "w"); fprintf (fich, "%s", body); free (body); fclose (fich); printf ("Le fichier '%s' a été écrit.\n", fichier_corps); free (fichier_corps); printf ("La requête suivante va être exécutée :\n%s\n", req1); executer (req1); } else { printf ("Création annulée, pas de newsgroup.\n"); } free (req1); } char ** nouveau_t () { char ** t = malloc (LMXSIZ * sizeof (char*)); int i; for (i = 0; i < LMXSIZ; i++) { t[i] = malloc (LMXSIZ); }; return t; } void maj_refs (PGconn * conn, char * id, char * anc_id1, char * nouv_id1) { int numfich = 0; char * req; asprintf (&req, "select numero_fichier from messages where id = '%s'", id); PGresult * res = PQexec (conn, req); free (req); sscanf (PQgetvalue(res, 0, 0), "%d", &numfich); numfich++; char * snumfich; asprintf (&snumfich, "%d", numfich); char * fichier_interm = fichier (id, snumfich); free (snumfich); char * snumfichp; asprintf (&snumfichp, "%d", numfich - 1); char * fichier_avant = fichier (id, snumfichp); free (snumfichp); FILE * f1 = fopen (fichier_avant, "r"); FILE * f2 = fopen (fichier_interm, "w"); free (fichier_avant); free (fichier_interm); char * ligne = malloc (LMXSIZ); int ligne_blanche = 0; char ** t; int i, n; char * refer = malloc (13); strcpy (refer, "REFERENCES: "); char * refer2; char * tampon; while (!(feof (f1))) { if (tampon != NULL) fputs (tampon, f2); fgets(ligne, LMXSIZ, f1 ); if (ligne_blanche == 0 && \ (strcmp (ligne, "\n") == 0 || strcmp (ligne, "") == 0)) ligne_blanche = 1; if (ligne_blanche == 0 && \ strcasecmp (ligne, "REFERENCES: ") > 0 && \ strcmp (ligne, "REFERENCES:!") < 0) { t = nouveau_t (); n = parse (&ligne[12], t, 0, 0); for (i = 0; i < n; i++) { if (strcmp (anc_id1, t[i]) == 0) { asprintf (&refer2, "%s%s, ", refer, nouv_id1); refer = refer2; } else { asprintf (&refer2, "%s%s, ", refer, t[i]); }; free (refer); refer = refer2; free (t[i]); } free (tampon); refer[strlen(refer) - 2] = 0; asprintf (&tampon, "%s\n", refer); free (refer); free (t); } else { free (tampon); asprintf (&tampon, "%s", ligne); } }; free (tampon); fclose (f1); fclose (f2); asprintf (&req, \ "%s where id = '%s'", \ "update messages set numero_fichier = 1 + numero_fichier", \ id); PQexec (conn, req); free (req); } char * deplacer (PGconn * conn, char * id, time_t date, char * cdate, \ char * source, char * cible) { if (0 == strcmp (source, cible)) return id; printf ("Début du déplacement de %s\n", id); char * req; PGresult * res; asprintf (&req, \ "delete from messages_contis where message = '%s' and conti = '%s';", \ id, source); PQexec (conn, req); free (req); int numfich = 0; asprintf (&req, "select numero_fichier from messages where id = '%s'", id); res = PQexec (conn, req); free (req); if (0 == PQntuples (res)) return NULL; char * snumfichp = PQgetvalue (res, 0, 0); sscanf (snumfichp, "%d", &numfich); numfich++; char * snumfichs; asprintf (&snumfichs, "%d", numfich); printf ("%s\n", snumfichs); char * fichier_avant = fichier (id, snumfichp); char * fichier_interm = fichier (id, snumfichs); free (snumfichs); FILE * f1 = fopen (fichier_avant, "r"); FILE * f2 = fopen (fichier_interm, "w"); free (fichier_avant); char * ligne = malloc (LMXSIZ); int ligne_blanche = 0; char ** t; char * newsgrp = malloc (13); strcpy (newsgrp, "NEWSGROUPS: "); char * newsgrp2; int n = 0; int i; asprintf (&req, \ "%s = '%s'; %s = '%s' and conti = '%s';", \ "update messages set numero_fichier = 1+ numero_fichier where id", \ id, \ "select message from messages_contis where message", \ id, cible); res = PQexec (conn, req); free (req); int dans_cible = (0 != PQntuples (res)); char * tampon = NULL; while (!(feof (f1))) { if (tampon != NULL) fputs (tampon, f2); fgets (ligne, LMXSIZ, f1); if (ligne_blanche == 0 && \ (strcmp (ligne, "\n") == 0 || strcmp (ligne, "") == 0)) ligne_blanche = 1; if (ligne_blanche == 0 && \ strcasecmp (ligne, "NEWSGROUPS: ") > 0 && \ strcasecmp (ligne, "NEWSGROUPS:!") < 0) { t = nouveau_t (); n = parse (&ligne[12], t, 0, 0); for (i = 0; i < n - 1; i++) { if (strcmp (source, t[i]) == 0) { if (!dans_cible) { asprintf (&newsgrp2, "%s%s, ", newsgrp, cible); free (newsgrp); newsgrp = newsgrp2; } } else { asprintf (&newsgrp2, "%s%s, ", newsgrp, t[i]); free (newsgrp); newsgrp = newsgrp2; }; free (t[i]); } free (t); free (tampon); newsgrp[strlen (newsgrp - 2)] = 0; asprintf (&tampon, "%s\n", newsgrp); } else { free (tampon); asprintf (&tampon, "%s", ligne); } }; free (tampon); fclose (f1); fclose (f2); if (dans_cible) { free (fichier_interm); return id; }; char * nouv_id = creer_id (date); char * nouv_fichier = fichier (nouv_id, "0"); rename (fichier_interm, nouv_fichier); free (fichier_interm); free (nouv_fichier); asprintf (&req, " select de from refs where a = '%s' ;", id); res = PQexec (conn, req); free (req); n = PQntuples (res); for (i = 0; i < n ; i++) { maj_refs (conn, PQgetvalue (res, i, 0), id, nouv_id); }; /* màj du champ fils du père du message à déplacer */ asprintf (&req, "select pere from messages where id = '%s'; ", id); res = PQexec (conn, req); free (req); char * pere = PQgetvalue (res, 0, 0); char * req2; if (0 == strcmp (pere, "")) { printf ("Le message '%s' n'a pas de père.\n",id); req2 = malloc (1); req2[0] = 0; } else { asprintf (&req, "select fils from messages where id = '%s'; ", pere); res = PQexec (conn, req); free (req); t = nouveau_t (); n = parse (PQgetvalue (res, 0, 0) , t, 0, 0); char * fils = malloc (1); fils[0] = 0; char * fils2; for (i = 0; i < n - 1 ; i++) { if (strcmp (t[i], id) == 0) asprintf (&fils2, "%s%s, ", fils, nouv_id); else asprintf (&fils2, "%s%s, ", fils, t[i]); free (fils); fils = fils2; }; asprintf (&req2, "update messages set fils = '%s' where id = '%s';", \ fils, pere); }; asprintf (&req, "%s %s '%s' %s '%s'; %s '%s' %s '%s'; %s '%s' %s '%s'; %s '%s', %s '%s' %s '%s'; %s ('%s', '%s', (%s '%s')); %s '%s';", \ req2, \ "update messages set pere =", nouv_id, "where pere =", id, \ "update refs set a =", nouv_id, "where a =", id, \ "update refs set de =", nouv_id, "where de =", id, \ "update messages set id =", nouv_id, \ "numero_fichier = 0, date =", cdate, \ "where id =", id, \ "insert into messages_contis(message,conti,numero) values", \ nouv_id, cible, \ "select prochain_numero from contis where nom =", cible, \ "update contis set prochain_numero = 1 + prochain_numero where nom =", \ cible); free (req2); printf ("\nLe message '%s' du conti '%s' devient le message '%s' du conti '%s'\n%s\n", \ id, source, nouv_id, cible, req); PQexec (conn, req); free (req); return nouv_id; } void deplacer_message (char *utilisateur, char * id, char * source, char * cible) { time_t date = time (NULL); char * cdate = ctime (&date); cdate[24] = 0; PGconn * conn = connecter (); char * req; asprintf (&req, "select * from droits where conti = '%s' and moderateur = '%s'", \ source, utilisateur); PGresult * res = PQexec (conn, req); free (req); if (PQntuples(res) == 0) { printf ("L'utilisateur '%s' n'a pas le droit de déplacer des messages depuis le conti '%s'.\n", \ utilisateur, source); return; }; asprintf (&req, "%s '%s' and (contis.lecture_seule = 'f' or (%s '%s'))", \ "select * from droits,contis where contis.nom =", cible, \ "droits.conti = contis.nom and droits.ecrire = 't' and droits.moderateur =", \ utilisateur); res = PQexec (conn, req); free (req); if (PQntuples(res) == 0) { printf("L'utilisateur '%s' n'a pas le droit de déplacer des messages vers le conti '%s'.\n", \ utilisateur, cible); return; }; PQexec (conn, \ "begin; lock refs,messages,messages_contis in exclusive mode; lock contis in row exclusive mode;"); srandom (date); free (deplacer (conn, id, date, cdate, source, cible)); PQexec (conn, "commit;"); deconnecter (conn); } void deplacer_fils_rec (PGconn * conn, char * rootid, time_t date, char * cdate, \ char * source, char * cible) { char * nouv_rootid = deplacer (conn, rootid, date, cdate, source, cible); if (NULL == nouv_rootid) return; char * req; asprintf (&req, \ "select messages.id from messages,messages_contis where messages.id = messages_contis.message and messages_contis.conti = '%s' and messages.pere = '%s';", \ source, nouv_rootid); PGresult * res = PQexec (conn, req); free (req); int n = PQntuples (res); int i; for (i = 0; i < n; i++) { deplacer_fils_rec (conn, PQgetvalue (res, i, 0), date, cdate, \ source, cible); } free (nouv_rootid); } void deplacer_thread (char * utilisateur, char * rootid, char * source, char * cible) { time_t date = time (NULL); char * cdate = ctime (&date); cdate[24] = 0; PGconn * conn = connecter (); char * req; asprintf(&req, \ "select * from droits where conti = '%s' and moderateur = '%s'", \ source, utilisateur); PGresult * res = PQexec (conn, req); free (req); if (PQntuples(res) == 0) { printf("L'utilisateur '%s' n'a pas le droit de déplacer des messages depuis le conti '%s'.\n", \ utilisateur, source); return; }; asprintf (&req, "select * from droits,contis where contis.nom = '%s' and (contis.lecture_seule = 'f' or (droits.conti = contis.nom and droits.moderateur = '%s' and droits.ecrire = 't') )", \ cible, utilisateur); res = PQexec(conn, req); free(req); if( PQntuples(res) == 0) { printf ("L'utilisateur '%s' n'a pas le droit de déplacer des messages vers le conti '%s'.\n", \ utilisateur, cible); return; }; PQexec (conn, \ "begin; lock refs,messages,messages_contis in exclusive mode; lock contis in row exclusive mode;"); srandom (date); deplacer_fils_rec (conn, rootid, date, cdate, source, cible); PQexec (conn, "commit;"); deconnecter (conn); }