// ZazouNICUpdate.cpp : définit le point d'entrée pour l'application DLL. // // TODO: Mettre les chaînes en ressources pour l'internationalisation #include "stdafx.h" #include #include #include "resource.h" #include "ZazouNICUpdate.h" // Le domaine sur lequel on travaille #define NIC_DOMAIN "www.zmws.net" // La base de l'uri où mettre à jour le nom de domaine #define URI_BASE "/nic/update?hostname=" // La base de l'uri où récupérer l'IP #define URI_IP "/nic/wsmyip" // Le contexte static struct _znucontext { char* hostname; char* login; char* password; char* serverMsg; std::string UIResult; HINSTANCE hInstance; unsigned long age; unsigned long ip; } gContext; BOOL WriteConfigFileOnUnload; /*************************/ /* Déclarations internes */ /*************************/ // Appelée lors du Chargement/Déchargement de la DLL BOOL APIENTRY DllMain ( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ); // Fonction utilitaire pour récupérer une chaîne char* ZGetStringFromUrl (const char* domain, const char * url, const char* login, const char* password); // Interprète la réponse du serveur int ZParseServerResp (const char* serverResp); // Fonction utilitaire pour récupérer une chaîne dans un contrôle char* ZGetControlString (int ctlid); // Fonction utilitaire pour affecter une chaîne à un contrôle void ZSetControlString (HWND hDlg, int ctlid, char* buff); int ZReadConfig (); int ZWriteConfig (); // Le callback pour la boîte de dialogue LRESULT CALLBACK confDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); /*******************/ /* Implémentations */ /*******************/ // Appelée lors du Chargement/Déchargement de la DLL BOOL APIENTRY DllMain ( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: WriteConfigFileOnUnload = TRUE; memset (&gContext, 0, sizeof(gContext)); gContext.hInstance = (HINSTANCE)hModule; ZReadConfig(); break; case DLL_PROCESS_DETACH: if (WriteConfigFileOnUnload) { ZWriteConfig(); } free (gContext.hostname); free (gContext.login); free (gContext.password); free (gContext.serverMsg); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; } return TRUE; } // Informe la dll si elle doit ou non écrire la config lors du déchargement void ZNICUpdateWriteConfigFileOnUnload(BOOL WriteIt) { WriteConfigFileOnUnload = WriteIt; } // Affiche la boîte de dialogue permettant la configuration int ZNICUpdateOptionsDialog(void) { INT_PTR ret; ret = DialogBox (gContext.hInstance, (LPCTSTR)IDD_CONFIG_DLG, NULL, (DLGPROC)confDlgProc); if (ret) { return RETCODE_NOT_CONFIGURED; } return RETCODE_SUCCESS; } // Programme ZNICUpdateNoUI pour une exécution toutes les 5 minutes int ZNICUpdateAuto(void) { // Porc inside (tm) // ToDo : UI Spécifique pour Status et Start/Stop static HANDLE thread_HANDLE = INVALID_HANDLE_VALUE; if (thread_HANDLE == INVALID_HANDLE_VALUE) { // Crée le thread s'il ne tourne pas DWORD tid; thread_HANDLE = (HANDLE)CreateThread(NULL, 0, ZNICUpdateAutoThread, NULL, 0, &tid); } else { // Supprime le thread s'il tourne // Remplacer ça par un signalement quelconque TerminateThread(thread_HANDLE, 0); CloseHandle (thread_HANDLE); thread_HANDLE = INVALID_HANDLE_VALUE; } return RETCODE_SUCCESS; } DWORD WINAPI ZNICUpdateAutoThread(LPVOID dummy) { int ret; unsigned long ip; // Porc inside (tm) // Remplacer ça par un signalement quelconque while (1) { ip = ZNICUpdateGetCurrentIP(); if (ip != gContext.ip) { ret = ZNICUpdateNoUI(); if (ret == RETCODE_NOT_CONFIGURED) { MessageBox (NULL, "ZazouNICUpdate non configuré", "ZazouNICUpdate", MB_ICONERROR); ret = ZNICUpdateOptionsDialog (); if (ret != RETCODE_SUCCESS) { return ret; } ZNICUpdateNoUI(); } } Sleep(300000); } return 0; } // Fait la mise à jour d'un sous domaine de zmws.net int ZNICUpdate(void) { INT_PTR ret; int retcode = RETCODE_UNKNOWN; char* uri = NULL; char* servResp = NULL; if (!( gContext.hostname && gContext.login && gContext.password )) { MessageBox (NULL, "ZazouNICUpdate non configuré", "ZazouNICUpdate", MB_ICONERROR); ret = ZNICUpdateOptionsDialog (); if (ret != RETCODE_SUCCESS) { return retcode; } } if (!( gContext.hostname && gContext.login && gContext.password )) { return retcode; } uri = (char*)malloc(strlen(URI_BASE)+strlen(gContext.hostname)+1); if (!uri) { return RETCODE_MEMFULL_ERR; } strcpy (uri, URI_BASE); strcat (uri, gContext.hostname); servResp = ZGetStringFromUrl (NIC_DOMAIN, uri, gContext.login, gContext.password); if (servResp) { retcode = ZParseServerResp (servResp); free (servResp); } switch (retcode) { case RETCODE_UNKNOWN: MessageBox (NULL, "Erreur inconnue ...", "ZazouNICUpdate", MB_ICONERROR); break; case RETCODE_MEMFULL_ERR: MessageBox (NULL, "Mémoire insuffisante ...", "ZazouNICUpdate", MB_ICONERROR); break; default: MessageBox (NULL, gContext.UIResult.c_str(), "ZazouNICUpdate", (retcode == RETCODE_SUCCESS) ? MB_ICONINFORMATION : MB_ICONERROR); break; } return retcode; } // Fait la mise à jour d'un sous domaine de zmws.net sans interface int ZNICUpdateNoUI(void) { int retcode = RETCODE_UNKNOWN; char* uri = NULL; char* servResp = NULL; if (!( gContext.hostname && gContext.login && gContext.password )) { return RETCODE_NOT_CONFIGURED; } uri = (char*)malloc(strlen(URI_BASE)+strlen(gContext.hostname)+1); if (!uri) { return RETCODE_MEMFULL_ERR; } strcpy (uri, URI_BASE); strcat (uri, gContext.hostname); servResp = ZGetStringFromUrl (NIC_DOMAIN, uri, gContext.login, gContext.password); if (servResp) { retcode = ZParseServerResp (servResp); free (servResp); } return retcode; } // Récupère l'IP externe connue unsigned long ZNICUpdateGetCurrentIP (void) { INT_PTR ret; char* uri = NULL; char* servResp = NULL; unsigned long ip = 0; if (!( gContext.hostname && gContext.login && gContext.password )) { MessageBox (NULL, "ZazouNICUpdate non configuré", "ZazouNICUpdate", MB_ICONERROR); ret = DialogBox (gContext.hInstance, (LPCTSTR)IDD_CONFIG_DLG, NULL, (DLGPROC)confDlgProc); if (ret) { return ip; } } if (!( gContext.hostname && gContext.login && gContext.password )) { return ip; } uri = (char*)malloc(strlen(URI_IP)+1); if (!uri) { return ip; } strcpy (uri, URI_IP); servResp = ZGetStringFromUrl (NIC_DOMAIN, uri, gContext.login, gContext.password); if (servResp) { ip = inet_addr (servResp); free (servResp); } return ip; } // Récupère l'IP externe connue unsigned long ZNICUpdateGetLastIP (void) { return (gContext.ip); } // Récupère l'heure de dernière mise à jour sur serveur unsigned long ZNICUpdateGetLastIPAge (void) { // si age == 0 renvoie la valeur de time (NULL) return (unsigned long)(time(NULL) - gContext.age); } const char* ZNICUpdateGetServerMessage (void) { if (gContext.serverMsg) return (gContext.serverMsg); else return (""); } // Récupère le sous domaine actuel const char* ZNICUpdateGetConfiguredDomain (void) { if (gContext.hostname) return (gContext.hostname); else return (""); } // Récupère le login actuel const char* ZNICUpdateGetConfiguredLogin (void) { if (gContext.login) return (gContext.login); else return (""); } // Récupère le mot de passe actuel const char* ZNICUpdateGetConfiguredPassword (void) { if (gContext.password) return (gContext.password); else return (""); } // Configure ZazouNICUpdate // Retourne -1 en cas d'erreur, 0 sinon int ZNICUpdateConfigure(const char* domain, const char* login, const char* passwd) { int ret = 0; if (domain) { if (gContext.hostname) { free (gContext.hostname); gContext.hostname = NULL; } gContext.hostname = (char*)malloc (strlen(domain)+1); if (gContext.hostname) { strcpy (gContext.hostname, domain); } else { ret = -1; } } if (login) { if (gContext.login) { free (gContext.login); gContext.login = NULL; } gContext.login = (char*)malloc (strlen(login)+1); if (gContext.login) { strcpy (gContext.login, login); } else { ret = -1; } } if (passwd) { if (gContext.password) { free (gContext.password); gContext.password = NULL; } gContext.password = (char*)malloc (strlen(passwd)+1); if (gContext.password) { strcpy (gContext.password, passwd); } else { ret = -1; } } return ret; } // Fonction utilitaire pour récupérer une chaîne char* ZGetStringFromUrl(const char* domain, const char* uri, const char* login, const char* password) { char* buff = NULL; // Initialisation HINTERNET hInternet = InternetOpen( "ZazouNicUpdate/1.1", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hInternet) return buff; // Initialisation session HINTERNET hSession = InternetConnect( hInternet, domain, INTERNET_DEFAULT_HTTP_PORT, login, password, INTERNET_SERVICE_HTTP, 0, NULL); if (!hSession) { InternetCloseHandle (hInternet); return buff; } // HINTERNET hRequest = HttpOpenRequest( hSession, "GET", uri, NULL, "ZazouNicUpdate Plugin v1.1", NULL, 0, NULL ); if (!hSession) { InternetCloseHandle (hSession); InternetCloseHandle (hInternet); return buff; } BOOL reqRC = HttpSendRequest( hRequest, NULL, 0, NULL, 0 ); if (reqRC) { DWORD dwSize; if (InternetQueryDataAvailable(hRequest,&dwSize,0,0)) { buff = (char*)malloc (dwSize+1); if (buff) { DWORD bytesRead; memset (buff, 0, dwSize+1); InternetReadFile ( hRequest, buff, dwSize, &bytesRead ); if (bytesRead != dwSize) { free (buff); buff = NULL; } } } } // Cleanup InternetCloseHandle (hRequest); InternetCloseHandle (hSession); InternetCloseHandle (hInternet); return buff; } // Interprète la réponse du serveur int ZParseServerResp (const char* serverResp) { int retcode = RETCODE_UNKNOWN; if (gContext.serverMsg) free (gContext.serverMsg); gContext.serverMsg = (char *)malloc (strlen(serverResp)+1); if (!gContext.serverMsg) return RETCODE_MEMFULL_ERR; strcpy(gContext.serverMsg, serverResp); if (!strcmp(serverResp, "badauth")) { gContext.UIResult = "Erreur d'authentication.\nVérifiez votre login et votre mot de passe.\n"; return RETCODE_BADAUTH; } if (!strcmp(serverResp, "badagent")) { gContext.UIResult = "Un problème technique (badagent) empêche le fonctionnement de ce plugin.\n"; return RETCODE_BADAGENT; } if (!strcmp(serverResp, "!donator")) { gContext.UIResult = "Cette fonctionnalité est réservée aux donateurs.\n"; return RETCODE_NOT_DONATOR; } if (!strcmp(serverResp, "notfqdn")) { gContext.UIResult = "Le nom de domaine semble incorrect.\n"; return RETCODE_NOT_FQDN; } if (!strcmp(serverResp, "nohost")) { gContext.UIResult = "Le nom de domaine n'a pas été transmis.\n"; return RETCODE_NO_HOST; } if (!strcmp(serverResp, "!yours")) { gContext.UIResult = "Ce domaine ne semble pas être à vous.\n"; return RETCODE_NOT_YOURS; } if (!strcmp(serverResp, "numhost")) { gContext.UIResult = "Trop de domaines à mettre à jour.\n"; return RETCODE_NUMHOST; } if (!strcmp(serverResp, "abuse")) { gContext.UIResult = "Bloqué pour utilisation abusive.\n"; return RETCODE_ABUSE; } if (!strcmp(serverResp, "dnserr")) { gContext.UIResult = "Erreur de DNS.\n"; return RETCODE_DNSERR; } if (!strcmp(serverResp, "911")) { gContext.UIResult = "Erreur interne du serveur.\n"; return RETCODE_911; } if (!strncmp(serverResp, "nochg ", 6) && strlen(serverResp)>6) { gContext.ip = inet_addr(serverResp+6); gContext.age = (unsigned long)time (NULL); gContext.UIResult = "Pas de changement pour ce domaine.\nIP: "; gContext.UIResult += (char*)(serverResp+6); gContext.UIResult += "\n"; return RETCODE_SUCCESS; } if (!strncmp(serverResp, "good ", 5) && strlen(serverResp)>5) { gContext.ip = inet_addr(serverResp+5); gContext.age = (unsigned long)time (NULL); gContext.UIResult = "Le domaine a été correctement mis à jour.\nIP: "; gContext.UIResult += (char*)(serverResp+5); gContext.UIResult += "\n"; return RETCODE_SUCCESS; } return retcode; } // Fonction utilitaire pour récupérer une chaîne dans un contrôle char* ZGetControlString (HWND hDlg, int ctlid) { HWND ctl; int txtlen; char* buff = NULL; ctl = GetDlgItem (hDlg, ctlid); if (ctl) { txtlen = GetWindowTextLength(ctl); buff = (char*)malloc (txtlen+1); if (buff) { memset (buff, 0, txtlen+1); GetWindowText (ctl, buff, txtlen+1); } } return buff; } // Fonction utilitaire pour affecter une chaîne à un contrôle void ZSetControlString(HWND hDlg, int ctlid, char* buff) { HWND ctl; if (buff) { ctl = GetDlgItem (hDlg, ctlid); if (ctl) { SetWindowText (ctl, buff); } } } int ZReadConfig () { // On cherche le fichier de config dans le répertoire _plugins.zmwsc std::ifstream ifs("_plugins.zmwsc/ZazouNICUpdate.zpc"); if (!ifs) { ifs.clear(); // S'il n'y est pas on tente le répertoire courant ifs.open ("ZazouNICUpdate.zpc"); if (!ifs.is_open()) { return 0; } } // On lit login, pass, domaine // A raison d'une entrée par ligne char tmp_char; int nlines = 0; std::string login; std::string password; std::string domain; while ((tmp_char = ifs.get()) != -1) { if ((tmp_char != '\r') && (tmp_char != '\n')) { if (tmp_char != ' ') { switch (nlines) { case 0: login += tmp_char; break; case 1: password += tmp_char; break; case 2: domain += tmp_char; break; } } } else { ++nlines; } } ifs.close(); if (login.length() && password.length() && domain.length()) { // Si on a login, pass et domaine, on configure le plugin. ZNICUpdateConfigure(domain.c_str(), login.c_str(), password.c_str()); } return 0; } int ZWriteConfig () { if (!(gContext.login && gContext.password && gContext.hostname)) return 0; std::ofstream ofs("_plugins.zmwsc/ZazouNICUpdate.zpc"); if (!ofs) { ofs.clear(); // S'il n'y est pas on tente le répertoire courant ofs.open ("ZazouNICUpdate.zpc"); if (!ofs.is_open()) { return 0; } } ofs << gContext.login << "\n"; ofs << gContext.password << "\n"; ofs << gContext.hostname << "\n"; ofs.close(); return 0; } // Le callback pour la boîte de dialogue LRESULT CALLBACK confDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; switch (message) { case WM_INITDIALOG: if ( gContext.hostname ) ZSetControlString (hDlg, IDC_DOMAINE, gContext.hostname); if ( gContext.login ) ZSetControlString (hDlg, IDC_LOGIN, gContext.login); if ( gContext.password ) ZSetControlString (hDlg, IDC_PASSWORD, gContext.password); break; case WM_COMMAND: { wmEvent = HIWORD(wParam); wmId = LOWORD(wParam); switch (wmId) { case IDOK: { // Nettoie le contexte ... if ( gContext.hostname ) free (gContext.hostname); if ( gContext.login ) free (gContext.login); if ( gContext.password ) free (gContext.password); // Récupère le contenu des champs texte ... gContext.hostname = ZGetControlString (hDlg, IDC_DOMAINE); gContext.login = ZGetControlString (hDlg, IDC_LOGIN); gContext.password = ZGetControlString (hDlg, IDC_PASSWORD); // Ferme le dialogue EndDialog(hDlg, 0); } break; case IDCANCEL: EndDialog(hDlg, 1); break; default: return DefWindowProc(hDlg, message, wParam, lParam); } } } return FALSE; }