;=====================================================================
; [spamMonitor] - (c) 2008 Jérôme Bruandet
;
; Sources + docs : http://spamcleaner.net/en/spammonitor/
;
;---------------------------------------------------------------------
; Detect any outgoing SMTP connection and alert user
;
; OS           : Windows (XP + Vista + Windows Server 2003/2008)
; Language     : Assembler
; Compiler     : Borland Tasm32
;
;---------------------------------------------------------------------
;
; License      : GPL (cf LICENSE.TXT)
;
;---------------------------------------------------------------------
; Revisions    :
;
; - v0.10      : 1st publication.
; - v0.20      : compatibility with old XP versions (+ XP SP1)
;                and Windows Server 2003 by using
;                AllocateAndGetTcpExTableFromStack API.
;
;=====================================================================

.586p
locals
jumps
.model flat, STDCALL

;=====================================================================
; constants and win32 API

include spammon.w32API
include spammon.w32const

;=====================================================================
.data

AppName        db "spammon",0
hInst          dd 0
RunningMsg     db "spamMonitor is already running !", 0
SMtitleMsg     db "spamMonitor", 0
DLLname        db "iphlpapi.dll", 0
DLLnotfoundMsg db "Error : cannot find [iphlpapi.dll] !"
               db 13,10,"Program halted.",0
; XP / Windows Server 2003 :
winOldAPIname  db "AllocateAndGetTcpExTableFromStack", 0
; XP SP2 / Vista / Windows Server 2003 SP1 / Windows Server 2008 :
winNewApiName  db "GetExtendedTcpTable",0
APInotfoundMsg db "Error : your operating system is not "
               db "compatible with spamMonitor ! Please read"
               db " the doc file.",13,10
               db "Program halted.", 0
APIsizeBuffer  dd 10240
APIaddress     dd 0
hProcess       dd 0
APIptr         dd 0
memAlloc       dd 0
APImemAlloc    dd 0
oldWinVer      db 0
hSnapshot      dd ?
uProcess       PROCESSENTRY32 <>
cxState        dd 0
remoteIP       dd 0
cx_buffer      dd 0
total_found    dd 0
dwStateBuffer  db 60 dup (0)
wc             WNDCLASS <?,offset WndProc,?,?,?,?,?,?,?,offset AppName>
CursorPos      POINT <?,?>
NIData         NOTIFYICONDATA <size NOTIFYICONDATA,0,'MAPS',\
               NIF_ICON+NIF_TIP+NIF_MESSAGE,WM_NOTIFYICON,0,\
               'Left/Right click'>
hMenu          dd ?
TrayIcon       dd ?
Message        MSG <?>
AboutDlgName   db "about",0
MainDlgName    db "main",0
stopThread     db 0
null           dd 0
dlgHandle      dd 0
dlgOpen        dd 0
helpURL        db "http://spamcleaner.net/en/spammonitor/?sp",0
scorgURL       db "http://spamcleaner.org/en/?sp",0
scnetURL       db "http://spamcleaner.net/en/?sp",0
openStr        db "open",0
confDelLogMsg  db "Delete [c:\spammon.log] ?",0
cantDelLogMsg  db "Error : cannot delete [c:\spammon.log] !", 0
noLBselectMsg  db "Select the program you want to kill in "
               db "the active SMTP connections listbox !", 0
cannotKillMsg  db "That process cannot be killed !",0
killMsg        db "The process has been killed !",0
CrashFormatMsg db "%lX",13,10,"- adress : 0x%.8lX",0
CrashMsg1      db "Argh, spamMonitor crashed !"
               db " Program will halt now.",13,10,13,10
               db "- error type : 0x"
CrashMsg2      db 32 dup (0)
Rect           RECT <>
screenX        dd ?
screenY        dd ?
notepad        db "notepad.exe",0
logFile        db "c:\spammon.log", 0
logFileHandle  dd 0
logFileHeader  db "Time",9,9,"Program",9,9,"IP address"
               db 9,"Connection",9,"PID",13,10
               db 68 dup (3dh),0
winPos         dd 0
GPLmsg         db "This program is free software: you can "
               db "redistribute it and/or modify it under the "
               db "terms of the GNU General Public License as "
               db "published by the Free Software Foundation, "
               db "either version 3 of the License, or (at your "
               db "option) any later version.",13,10,13,10
               db "This program is distributed in the hope that "
               db "it will be useful, but WITHOUT ANY WARRANTY; "
               db "without even the implied warranty of "
               db "MERCHANTABILITY or FITNESS FOR A PARTICULAR "
               db "PURPOSE. See the GNU General Public License "
               db "for more details.",13,10,13,10
               db "You should have received a copy of the GNU "
               db "General Public License along with this program. "
               db "If not, see <http://www.gnu.org/licenses/>.",13,10,13,10
               db "If the source code was not included with the "
               db "program, it can be donwloaded at : "
               db "<http://spamcleaner.net/en/spammonitor/>.",0
soundAlert     db "ALERT",0
ee             dd 0
ee_buffer      db 100 dup (0)
bWritten       dd 0
processID      dd 0
PIDbuffer      dd 0
processName    dd 0
noProcessName  db "??????????",0
tab_act        dd 20*4
               dd 35*4
               dd 250
tab_inact      dd 11*4
               dd 35*4
               dd 250
               dd 350
timeFormat     db 13,10,"hh:mm:ss",9,0
stringFormat   db '%s',9,'%i.%i.%i.%i',9,'[%hS]',9,'%i',0
timeBuffer     db 11 dup (0)
outBuffer      db 100 dup (0)

;=====================================================================
.code
Main  proc

   ; SEH just in case... :
   push     offset BetterSafeThanSorry
   call     SetUnhandledExceptionFilter

   ; only one instance :
   call     CreateMutexA, 0, 0, offset AppName
   mov      hInst, eax
   call     GetLastError
   cmp      eax, 183                         ; ERROR_ALREADY_EXISTS
   jne      not_running
   call     CloseHandle, hInst
   push     10h
   push     offset SMtitleMsg
   push     offset RunningMsg
   push     0
   call     MessageBoxA
   jmp      quit
not_running:
   ; try to find iphlpapi.dll :
   call     LoadLibraryA, offset DLLname
   test     eax, eax
   jnz      DLL_found
   push     10h
   push     offset SMtitleMsg
   push     offset DLLnotfoundMsg
   push     0
   call     MessageBoxA
   jmp      quit
DLL_found:
   mov      null, eax
   ; attempt to retrieve AllocateAndGetTcpExTableFromStack address
   ; (XP / Windows Server 2003) :
   call     GetProcAddress, eax, offset winOldAPIname
   test     eax, eax
   jz       isNewer
   mov      oldWinVer, 1
   mov      APIaddress, eax
   ; needed for the API call :
   call     GetProcessHeap
   mov      hProcess, eax
   jmp      API_found

isNewer:
   ; if error, test with GetExtendedTcpTable API (XP SP2 / Vista /
   ; Windows Server 2003 SP1 / Windows Server 2008) :
   call     GetProcAddress, null, offset winNewApiName
   test     eax, eax
   jnz      isNewer2
   push     10h
   push     offset SMtitleMsg
   push     offset APInotfoundMsg
   push     0
   call     MessageBoxA
   jmp      quit

isNewer2:
   mov      APIaddress, eax
   ; allocate a large (10Kb) buffer for TcpTable :
   call     GlobalAlloc,GHND, 10240
   mov      APImemAlloc, eax
   call     GlobalLock,eax
   mov      APIptr, eax

API_found:
   ; allocate 1Kb to store current SMTP connections
   ; (cx_buffer) + PIDs (PIDbuffer) :
   call     GlobalAlloc,GHND, 1024
   mov      memAlloc, eax
   call     GlobalLock,eax
   mov      cx_buffer, eax
   add      eax, 512
   mov      PIDbuffer, eax

   call     GetModuleHandleA, 0
   mov      hInst, eax

   mov      wc.w_hInstance, eax
   call     LoadMenuA, hInst, 103            ; menu
   mov      hMenu, eax
   call     LoadIconA, hInst, 101            ; icone
   mov      TrayIcon, eax
   mov      NIData.n_hIcon, eax
   mov      wc.w_hIcon, eax
   call     RegisterClassA, offset wc
   push     0
   push     hInst
   push     0
   push     0
   push     0
   push     0
   push     0
   push     0
   push     0
   push     0
   push     offset AppName
   push     0
   call     CreateWindowExA
   mov      NIData.n_hWnd, eax

   ; SMTP connections monitoring thread :
   push     offset null
   push     0
   push     0
   push     offset monitorThread
   push     0
   push     0
   call     CreateThread

   ; open main dialogbox :
   push     0
   push     IDM_CREATE
   push     111h
   push     dword ptr [NIData.n_hWnd]
   call     PostMessageA

   push     0
   push     80h
   push     2
   push     0
   push     1
   push     40000000h
   push     offset logFile
   call     CreateFileA
   mov      logFileHandle, eax
   call     lstrlenA, offset logFileHeader
   push     0
   push     offset bWritten
   push     eax
   push     offset logFileHeader
   push     logFileHandle
   call     WriteFile

messageLoop:
   call     GetMessageA, offset Message, 0, 0, 0
   or       eax, eax
   jz       endLoop
   call     TranslateMessage, offset Message
   call     DispatchMessageA, offset Message
   jmp      messageLoop

endLoop:
   call     Shell_NotifyIconA, NIM_DELETE, offset NIData

   cmp      oldWinVer, 1
   jz       noneed2free
   call     GlobalUnlock, [APImemAlloc]
   call     GlobalFree, [APImemAlloc]
noneed2free:
   call     GlobalUnlock, [memAlloc]
   call     GlobalFree, [memAlloc]
   call     CloseHandle, logFileHandle

quit:
   call     ExitProcess, 0

Main endp

;=====================================================================
; BetterSafeThanSorry : fetch address and exception code
;       (SEH) in EXCEPTION_RECORD structure (esp+4) in case of
;       a crash and display their values in a messagebox.

BetterSafeThanSorry proc

   mov      esi, dword ptr [esp+4]
   mov      esi, dword ptr [esi]
   mov      eax, dword ptr [esi+12]
   push     eax
   mov      eax, dword ptr [esi]
   push     eax
   push     offset CrashFormatMsg
   push     offset CrashMsg2
   call     _wsprintfA
   add      esp, 4*4
   push     40h
   push     offset SMtitleMsg
   push     offset CrashMsg1
   push     0
   call     MessageBoxA
   mov      stopThread, 1
   ; force return address :
   push     offset endLoop
   ret

BetterSafeThanSorry endp

;=====================================================================
; monitorThread : fetch active SMTP connections

monitorThread proc

next_round:

   cmp      oldWinVer, 1
   jnz      @newwin_01
   ; call to AllocateAndGetTcpExTableFromStack :
   push     2                                ; AF_INET
   push     0                                ; dwFlags
   push     hProcess                         ; hHeap
   push     0                                ; unsorted
   push     offset APIptr                    ; ppTcpTable
   call     dword ptr [APIaddress]
   test     eax, eax                         ; ERROR_SUCCESS (0) ?
   je       APIok
   jmp      goAhead

@newwin_01:
   ; call to GetExtendedTcpTable :
   push     0                                ; Reserved
   push     5                                ; TCP_TABLE_OWNER_PID_ALL
   push     2                                ; AF_INET
   push     0                                ; unsorted
   push     offset APIsizeBuffer             ; pdwSize
   push     [APIptr]                         ; pTcpTable
   call     dword ptr [APIaddress]
   cmp      eax, 122                         ; ERROR_INSUFFICIENT_BUFFER
   je       goAhead
APIok:
   mov      esi, [APIptr]                    ; pointe sur la structure
   test     esi, esi
   je       goAhead
   ; number of active connections :
   mov      ecx, [esi]
   test     ecx, ecx                         ; aucune ??
   je       goAhead

next_cx:
   push     ecx                              ; compteur
   push     esi                              ; pointeur

   ; is it SMTP port 25 ? :
   cmp      dword ptr [esi+14h], 1900h       ; dwRemotePort
   jne      unwanted

   ; get connection state :
   mov      eax, [esi+4]                     ; dwState
   mov      cxState, eax
   ; convert to ASCII string :
   add      eax, 12ch
   call     LoadStringA, hInst, eax, offset dwStateBuffer, 60

   ; find remote IP :
   mov      eax, dword ptr [esi+10h]         ; dwRemoteAddr
   mov      remoteIP, eax

   ; get application PID :
   mov      eax, [esi+18h]                   ; dwProcessId
   mov      processID, eax
   ; process name :
   call     getProcessName
   ; ensure we have found a name :
   cmp      byte ptr [processName], 0
   jne      nameOK
   mov      ebx, offset noProcessName
   mov      processName, ebx

nameOK:
   ; text to display :
   push     processID
   push     offset dwStateBuffer
   mov      ebx, remoteIP
   movzx    ebx, byte ptr [remoteIP+3]
   push     ebx
   movzx    ebx, byte ptr [remoteIP+2]
   push     ebx
   movzx    ebx, byte ptr [remoteIP+1]
   push     ebx
   movzx    ebx, byte ptr [remoteIP]
   push     ebx
   push     processName
   push     offset stringFormat
   push     offset outBuffer
   call     _wsprintfA
   add      esp, 4*9                         ; adjust stack

   ; check if already present in the listebox :
   push     offset outBuffer
   push     0
   push     LB_FINDSTRING
   push     IDC_ACTIVECX
   push     dlgHandle
   call     SendDlgItemMessageA
   cmp      eax, -1                          ; LB_ERR
   ; add to listbox if unknown :
   je       add2LB

   ; set position flag :
   mov      ebx, [cx_buffer]
   mov      dword ptr [ebx+eax*4], 1
   ; add its PID to PIDbuffer (cx_buffer+512) :
   mov      ecx, processID
   mov      [ebx+512+eax*4], ecx
   inc      total_found
   jmp      unwanted

add2LB:
   ; display in listbox :
   push     offset outBuffer
   push     0
   push     180h                             ; LB_ADDSTRING
   push     IDC_ACTIVECX
   push     dlgHandle
   call     SendDlgItemMessageA
   ; set position flag :
   mov      ebx, [cx_buffer]
   mov      dword ptr [ebx+eax*4], 1
   mov      ecx, processID
   mov      [ebx+512+eax*4], ecx
   inc      total_found

   ; log all data (+ time) :
   push     11
   push     offset timeBuffer
   push     offset timeFormat
   push     0
   push     8
   push     0
   call     GetTimeFormatA
   push     0
   push     offset bWritten
   push     11
   push     offset timeBuffer
   push     logFileHandle
   call     WriteFile
   call     lstrlenA, offset outBuffer
   push     0
   push     offset bWritten
   push     eax
   push     offset outBuffer
   push     logFileHandle
   call     WriteFile

   ; insert to the closed connections listbox :
   push     offset timeBuffer+2              ; bypass CR/LF
   push     0
   push     181h                             ; LB_INSERTSTRING
   push     IDC_INACTIVECX
   push     dlgHandle
   call     SendDlgItemMessageA

   ; open dialogbox if it is minimized :
   cmp      dlgOpen, 0
   jnz      dlgAlreadyOpen
   call     PostMessageA, dword ptr [NIData.n_hWnd], 111h, IDM_MAIN, 0
dlgAlreadyOpen:
   ; activate "Kill" boutton :
   call     GetDlgItem, dlgHandle, IDC_KILL
   call     EnableWindow, eax, 1
   ; flash + beep :
   call     FlashWindow,dlgHandle ,1
   ; sound alert ?
   call     IsDlgButtonChecked, dlgHandle, IDC_ALERTE
   test     eax, eax
   jz       noWave
   call     PlaySound, offset soundAlert, hInst, 42004h
   jmp      unwanted
noWave:
   call     MessageBeep, 40h

unwanted:
   pop      esi
   pop      ecx
   dec      ecx
   jcxz     noMoreCX
   add      esi, 18h
   jmp      next_cx

noMoreCX:
   cmp      oldWinVer, 1
   jnz      @newwin_02
   ; must free allocated memory after each call
   ; to AllocateAndGetTcpExTableFromStack :
   call     HeapFree, hProcess, 0, [APIptr]

@newwin_02:
   ; get number on items in the listbox :
   push     0
   push     0
   push     18bh                 ; LB_GETCOUNT
   push     IDC_ACTIVECX
   push     dlgHandle
   call     SendDlgItemMessageA
   push     eax
   test     eax, eax
   jnz      cleanupLB
   ; deactive "Kill bouton" if no connection :
   call     GetDlgItem, dlgHandle, IDC_KILL
   call     EnableWindow, eax, 0
   pop      eax
   jmp      goAhead
cleanupLB:
   pop      eax
   cmp      eax, [total_found]
   jb       goAhead

   ; clear connection buffer
   ; and update the listbox :
   mov      ebx, [cx_buffer]

@cleanup_loop:
   dec      eax                              ; zero-based
   cmp      eax, -1
   je       goAhead
   cmp      dword ptr [ebx+eax*4], 1
   jz       resetFlag
   push     eax
   push     0
   push     eax
   push     182h                             ; LB_DELETESTRING
   push     IDC_ACTIVECX
   push     dlgHandle
   call     SendDlgItemMessageA
   pop      eax
resetFlag:
   mov      dword ptr [ebx+eax*4], 0
   jmp      @cleanup_loop

goAhead:
   mov      dword ptr [total_found], 0
   call     Sleep, 150
   ; go ahead ?
   cmp      stopThread, 1
   jnz      next_round
   ret

monitorThread endp

;=====================================================================
; getProcessName : find a process name from its PID
; Param.         : processID == PID

getProcessName proc

   pushad
   mov      processName, 0
   call     CreateToolhelp32Snapshot, 2, 0   ; snapshot
   mov      [hSnapshot], eax
   mov      [uProcess.dwSize], size PROCESSENTRY32
   push     offset uProcess
   push     eax
   call     Process32First                   ; 1st proces
   test     eax, eax
   jnz      getnext
   popad
   ret

getnext:
   mov      eax, uProcess.th32ProcessID
   ; is that the one we are looking for ?
   cmp      eax, dword ptr [processID]
   jnz      unknown
   mov      eax, offset uProcess.szExeFile
   mov      processName, eax
   jmp      closeSnapshot
unknown:
   push     offset uProcess
   push     [hSnapshot]
   call     Process32Next                    ; next process
   test     eax, eax
   jnz      getnext

closeSnapshot:
   push     [hSnapshot]
   call     CloseHandle

   popad
   ret

getProcessName endp

;=====================================================================
; WndProc
; Param.  : hWnd, uMsg, wParam et lParam

WndProc     proc

   enter    0, 0
   push     ebx
   push     esi
   push     edi

wm_destroy:
   cmp      dword ptr [ebp+0ch], 2           ; uMsg == WM_DESTROY ?
   jnz      wm_command
   call     PostQuitMessage, 0
   jmp      clear_eax

wm_command:
   cmp      dword ptr [ebp+0ch], 111h        ; uMsg == WM_COMMAND ?
   jnz      wm_notify

create_dlg:
   cmp      word ptr [ebp+10h], IDM_CREATE   ; wParam == create ?
   jnz      menu_open
   ; remove systray icon :
   call     Shell_NotifyIconA, NIM_DELETE, offset NIData
   mov      dlgOpen, 1
   ; dialogbox creation :
   push     0
   push     offset MainDlg
   push     dword ptr [ebp+8]
   push     offset MainDlgName
   push     hInst
   call     DialogBoxParamA
   jmp      clear_eax

menu_open:
   cmp      word ptr [ebp+10h], IDM_MAIN     ; wParam == "Open" ?
   jnz      menu_about
   call     Shell_NotifyIconA, NIM_DELETE, offset NIData
   mov      dlgOpen, 1

   ; display dialogbox and move it to the lower
   ; right corner of the screen :
   mov      winPos, 1
   push     dlgHandle
   call     MoveDlgBox
   add      esp, 4
   call     ShowWindow, dlgHandle, 9         ; SW_RESTORE
   jmp      clear_eax

menu_about:
   cmp      word ptr [ebp+10h], IDM_ABOUT    ; wParam == "About" ?
   jnz      menu_exit
   push     0
   push     offset AboutDlg
   push     dword ptr [ebp+8]
   push     offset AboutDlgName
   push     hInst
   call     DialogBoxParamA
   jmp      clear_eax

menu_exit:
   cmp      word ptr [ebp+10h], IDM_EXIT     ; wParam == "Exit" ?
   jnz      def_win
   mov      stopThread, 1                    ; stop our thread
   push     dword ptr [ebp+8]
   call     DestroyWindow
   jmp      clear_eax

wm_notify:
   cmp      dword ptr [ebp+0ch], 400h        ; uMsg == WM_USER ?
   jnz      def_win

   cmp      dword ptr [ebp+14h], 205h        ; lParam == WM_RBUTTONUP ?
   jz       show_menu
   cmp      dword ptr [ebp+14h], 202h        ; lParam == WM_LBUTTONUP ?
   jnz      def_win

show_menu:
   call     GetCursorPos , offset CursorPos
   xor      ecx, ecx
   setnz    cl
   call     GetSubMenu, hMenu, ecx
   push     eax
   push     dword ptr[ebp+8]
   call     SetForegroundWindow
   pop      eax
   push     0
   push     dword ptr [ebp+8]
   push     0
   push     CursorPos.y
   push     CursorPos.x
   push     TPM_RIGHTBUTTON
   push     eax
   call     TrackPopupMenu
   call     PostMessageA, dword ptr [ebp+08h], 0, 0, 0
   jmp      clear_eax

def_win:
   push     dword ptr [ebp+14h]              ; lParam
   push     dword ptr [ebp+10h]              ; wParam
   push     dword ptr [ebp+0ch]              ; uMsg
   push     dword ptr [ebp+8]                ; hWnd
   call     DefWindowProcA
   jmp      Return
clear_eax:
   xor      eax, eax
Return:
   pop      edi
   pop      esi
   pop      ebx
   leave
   ; adjust stack
   retn     10h

WndProc     endp

;=====================================================================
; MainDlg : main dialogbox stuff

MainDlg proc

   push     ebp
   mov      ebp, esp
   cmp      dword ptr [ebp+0ch], 110h        ; uMsg == WM_INITDIALOG ?
   jnz      @wm_command

   push     dword ptr [ebp+8]
   mov      winPos, 1
   call     MoveDlgBox
   pop      dlgHandle                        ; fetch its handle
                                             ; and adjust stack
   ; initialize tabulations (active cx) :
   push     offset tab_act
   push     3
   push     192h                             ; LB_SETTABSTOPS
   push     IDC_ACTIVECX
   push     dlgHandle
   call     SendDlgItemMessageA

   ; initialize tabulations (inactive cx) :
   push     offset tab_inact
   push     4
   push     192h                             ; LB_SETTABSTOPS
   push     IDC_INACTIVECX
   push     dlgHandle
   call     SendDlgItemMessageA

   ; sound alert checkbox :
   call CheckDlgButton, dlgHandle, IDC_ALERTE, 1

   mov      eax, 1
   leave
   retn     10h

@wm_command:
   cmp      dword ptr [ebp+0ch], 111h        ; uMsg == WM_COMMAND
   jne      @clear_eax

@idc_ok:
   mov      eax, dword ptr [ebp+10h]
   and      eax, 0000FFFFh
   cmp      eax, IDC_OK                      ; wParam == "OK" ?
   jne      @idc_kill

   call     ShowWindow, dlgHandle, 0         ; SW_HIDE
   call     Shell_NotifyIconA, NIM_ADD, offset NIData
   mov      dlgOpen, 0
   jmp      @clear_eax

@idc_kill:
   cmp      eax, 1005                        ; wParam == "Kill !" ?
   jne      @idc_viewlog
   push     0
   push     0
   push     188h                             ; LB_GETCURSEL
   push     IDC_ACTIVECX
   push     dlgHandle
   call     SendDlgItemMessageA
   cmp      eax, -1                          ; LB_ERR
   jne      fetchLBtext
   push     30h
   push     offset SMtitleMsg
   push     offset noLBselectMsg
   push     dlgHandle
   call     MessageBoxA
   jmp      @clear_eax
fetchLBtext:
   mov      ebx, [PIDbuffer]
   mov      ebx, [ebx+eax*4]
   test     ebx, ebx
   jnz      @kill_it
@cannotKill:
   push     10h
   push     offset SMtitleMsg
   push     offset cannotKillMsg
   push     dlgHandle
   call     MessageBoxA
   jmp      @clear_eax
@kill_it:
   push     ebx
   push     1
   push     1                                ; PROCESS_TERMINATE
   call     OpenProcess
   test     eax, eax
   jz       @cannotKill
   push     0
   push     eax
   call     TerminateProcess
   test     eax, eax
   jz       @cannotKill
   push     40h
   push     offset SMtitleMsg
   push     offset killMsg
   push     dlgHandle
   call     MessageBoxA
   jmp      @clear_eax

@idc_viewlog:
   cmp      eax, IDC_VIEWLOG                 ; wParam == "Voir Log" ?
   jne      @idc_dellog
   push     1
   push     0
   push     0
   push     offset logFile
   push     offset openStr
   push     offset notepad
   call     ShellExecuteA
   jmp      @clear_eax

@idc_dellog:
   cmp      eax, IDC_DELLOG                  ; wParam == "Effacer Log" ?
   jne      @idc_about

   ; erase log file :
   push     31h
   push     offset SMtitleMsg
   push     offset confDelLogMsg
   push     dlgHandle
   call     MessageBoxA
   cmp      eax, 1
   jnz      @clear_eax
   call     CloseHandle, logFileHandle
   push     0
   push     80h
   push     2
   push     0
   push     1
   push     40000000h
   push     offset logFile
   call     CreateFileA
   mov      logFileHandle, eax
   call     lstrlenA, offset logFileHeader
   push     0
   push     offset bWritten
   push     eax
   push     offset logFileHeader
   push     logFileHandle
   call     WriteFile
   cmp      bWritten, 0
   jnz      @clear_eax
   push     10h
   push     offset SMtitleMsg
   push     offset cantDelLogMsg
   push     dlgHandle
   call     MessageBoxA
   jmp      @clear_eax

@idc_about:
   cmp      eax, IDC_ABOUT                   ; wParam == "About..." ?
   jne      @idc_help

   push     0
   push     offset AboutDlg
   push     dword ptr [ebp+8]
   push     offset AboutDlgName
   push     hInst
   call     DialogBoxParamA
   jmp      @clear_eax

@idc_help:
   cmp      eax, IDC_HELP                    ; wParam == "Help" ?
   jne      @clear_eax

   ; run browser :
   push     1
   push     0
   push     0
   push     offset helpURL
   push     offset openStr
   push     0
   call     ShellExecuteA

@clear_eax:
   xor      eax, eax
   leave
   retn     10h

MainDlg endp

;=====================================================================
; AboutDlg  : "About" dialogbox
AboutDlg Proc

   push  ebp
   mov   ebp, esp

@@wm_initdialog:
   cmp      dword ptr [ebp+0ch], 110h        ; WM_INITDIALOG
   jnz      @@wm_command

   push     dword ptr [ebp+8]
   mov      winPos, 0
   call     MoveDlgBox
   add      esp, 4

   push     offset GPLmsg
   push     IDC_GLP
   push     dword ptr [ebp+08h]
   call     SetDlgItemTextA
   mov      eax, 1
   leave
   retn     10h
@@wm_command:
   cmp      dword ptr [ebp+0ch], 111h                 ; WM_COMMAND
   jne      @@wm_notify
   mov      eax, dword ptr [ebp+10h]
   and      eax, 0000FFFFh
   cmp      eax, IDC_OK
   jne      @@idc_scorg
@@end_dialog:
   call     Shell_NotifyIconA, NIM_ADD, offset NIData
   call     EndDialog, dword ptr [ebp+08h], 0
   mov      eax, 1
   leave
   retn     10h
@@idc_scorg:
   cmp      eax, IDC_SCORG
   jne      @@is_scnet
   mov      eax, offset scorgURL
@@website:
   push     1
   push     0
   push     0
   push     eax
   push     offset openStr
   push     0
   call     ShellExecuteA
   jmp      @@end_dialog
@@is_scnet:
   cmp      eax, IDC_SCNET
   jne      @@is_icon
   mov      eax, offset scnetURL
   jmp      @@website

@@is_icon:
   cmp      eax, 2121
   jne      @@clear_eax
   cmp      word ptr [ebp+12h], 1
   jne      @@clear_eax
   cmp      dword ptr [ee], 4
   jb       @@clear_eax
   mov      stopThread, 1
   call     PostMessageA, dword ptr [NIData.n_hWnd], 111h, IDM_EXIT, 0
   jmp      @@end_dialog
@@wm_notify:
   cmp      dword ptr [ebp+0ch], 206h
   jne      @@clear_eax
   cmp      word ptr [ebp+10h], 0ah
   jne      @@clear_eax
@@easter_egg_inside:
   inc      dword ptr [ee]
   cmp      dword ptr [ee], 1
   jb       @@clear_eax
   cmp      dword ptr [ee], 4
   je       ee_thread
   cmp      dword ptr [ee], 3
   ja       @@clear_eax
   push     40h
   push     offset SMtitleMsg
   mov      eax, [ee]
   add      eax, 989
   call     LoadStringA, hInst, eax, offset ee_buffer, 100
   push     offset ee_buffer
   push     dword ptr [ebp+8]
   call     MessageBoxA
   jmp      @@clear_eax
ee_thread:
   mov      stopThread, 1
   call     Sleep, 250
   call     EnableMenuItem, hMenu, IDM_EXIT, 1
   mov      ecx, 6
@@ee_nextbtn:
   mov      eax, ecx
   add      eax, 949
   mov      ebx, ecx
   add      ebx, 999
   push     ecx
   call     LoadStringA, hInst, eax, offset ee_buffer, 100
   call     SetDlgItemTextA, dlgHandle, ebx, offset ee_buffer
   pop      ecx
   loop     @@ee_nextbtn
   mov      stopThread, 0
   call     CreateThread, 0, 0, offset eeThread, 0, 0, offset null
   jmp      @@end_dialog

@@clear_eax:
   xor      eax, eax
   leave
   retn     10h

AboutDlg    endp

eeThread    proc
@@next_ee:
   cmp      dlgOpen, 1
   je       @@ee_open
   call     PostMessageA, dword ptr [NIData.n_hWnd], 111h, IDM_MAIN, 0
   mov      dlgOpen, 1
@@ee_open:
   call     SendDlgItemMessageA, dlgHandle, 1007, 184h, 0, 0
   mov      ecx, 0fh
   mov      ebx, ecx
   add      ebx, 900
@@ee_nextitm:
   push     ecx
   call     LoadStringA, hInst, ebx, offset ee_buffer, 100
   call     GetTickCount
   and      eax, 0fh
   push     offset ee_buffer
   push     0
   cmp      al, 8
   jb       @@ins
   push     180h
   jmp      @@add
@@ins:
   push     181h
@@add:
   push     IDC_ACTIVECX
   push     dlgHandle
   call     SendDlgItemMessageA
   pop      ecx
   dec      ebx
   loop     @@ee_nextitm
   call     PlaySound, offset soundAlert, hInst, 42004h
   call     Sleep, 100
   call     FlashWindow, dlgHandle, 1
   cmp      stopThread, 1
   jnz      @@next_ee
   ret

eeThread    endp
;=====================================================================
; MoveDlgBox : dialogbox positionning
; Param.     : - winPos  : 0 (center) ou 1 (lower right)
;              - [esp+4] : dialogbox handle

MoveDlgBox  proc

   push     offset Rect
   push     dword ptr [esp+8]
   call     GetWindowRect
   call     GetSystemMetrics, 16             ; SM_CXFULLSCREEN
   mov      esi, eax
   cmp      winPos, 0
   jnz      @1
   shr      esi, 1
   jmp      @2
@1:
   sub      esi, 10
@2:
   mov      eax, Rect.right
   sub      eax, Rect.left
   cmp      winPos, 0
   jnz      @3
   shr      eax, 1
@3:
   sub      esi, eax
   call     GetSystemMetrics, 17             ; SM_CYFULLSCREEN
   cmp      winPos, 0
   jnz      @4
   shr      eax, 1
   jmp      @5
@4:
   add      eax, 10
@5:
   mov      ecx, Rect.bottom
   sub      ecx, Rect.top
   cmp      winPos, 0
   jnz      @6
   shr      ecx, 1
@6:
   sub      eax, ecx
   push     0
   mov      ebx, Rect.bottom
   sub      ebx, Rect.top
   push     ebx
   mov      ebx, Rect.right
   sub      ebx, Rect.left
   push     ebx
   push     eax
   push     esi
   push     dword ptr [esp+18h]
   call     MoveWindow
   ret

MoveDlgBox     endp
;=====================================================================

End      Main

;=====================================================================