home *** CD-ROM | disk | FTP | other *** search
- /* NET.C - Network window procedure for WSMTPSRV
- - WinSock V1.1 required
-
- Author: Ian Blenke
-
- Ian Blenke cannot be held responsible for damages, expressed or implied, for
- the use of this software. No commercial use can be made of this product
- without the consent of the author. No profit of any kind can be made on the
- sale or distribution of this program. If you wish to distribute this program
- with other samples of WinSock programming, you must first contact the author
- so that he can keep accurate records of its usage. If you write any programs
- based on this source code, you may not sell them for any profit without the
- written consent of the author. If you incorporate this source code into a
- public domain program, all the author requires is a notification that "part
- of the code was written by Ian Blenke" and some form of notification that
- his name was used in the public domain software distribution. This does not
- represent a contract on the part of the author. If any issues cannot clearly
- be resolved by reading this text, immediately contact the author.
-
- If you have any bug reports and/or source patches... By all means, tell me! I
- would be glad to help keep this code up to date. Do not, however, modify this
- source in any way and re-distribute it without the author's knowledge. This
- would constitute something not-good.
-
- I don't like such agreements, but in today's world of lawyers and lawbreakers
- I have little other choice. Enjoy!
- */
-
- #ifndef NET_C
- #define NET_C
- #include "Net.H"
- #include "Dialogs.h"
-
- #include <Time.h> // DOS Time functions for netGetTimeAndDate()
-
-
- /* BOOL netInit(void);
- Purpose: To initialize the network window
- Given: Nothing.
- Returns: TRUE if an error occured.
- */
- BOOL netInit(void)
- {
- WNDCLASS wndclass;
- SOCKADDR_IN saMain;
- LPSERVENT lpseServEnt;
- LPHOSTENT lpheHostEnt;
- BOOL bDebug;
-
- if(gethostname((LPSTR)szLocalHostName,
- sizeof(szLocalHostName)) == SOCKET_ERROR)
- {
- // We need SOME valid name - make it "Unknown"
- lstrcpy((LPSTR)szLocalHostName, (LPSTR)STRING_UNKNOWN);
- }
- else
- {
- lpheHostEnt=gethostbyname((LPSTR)szLocalHostName);
- if(lpheHostEnt!=NULL)
- {
- lstrcpy((LPSTR)szLocalHostName, lpheHostEnt->h_name);
- }
- }
-
- lstrcpy((LPSTR)szNetworkClass, (LPSTR)CLASS_NETWORK);
-
- wndclass.style = 0;
- wndclass.lpfnWndProc = (WNDPROC)NetProc;
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = 0;
- wndclass.hInstance = hInst;
- wndclass.hIcon = NULL;
- wndclass.hCursor = NULL;
- wndclass.hbrBackground = NULL;
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = (LPSTR)szNetworkClass;
-
- if(!RegisterClass(&wndclass))
- {
- return(TRUE);
- }
-
- // Create the main "invisible" network window
- hWndMain=CreateWindow((LPSTR)szNetworkClass,
- (LPSTR)"",
- WS_CHILD,
- CW_USEDEFAULT, CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT,
- hWndDlg, NULL, hInst, NULL);
-
- if(!hWndMain)
- {
- UnregisterClass((LPSTR)szNetworkClass, hInst);
- return(TRUE);
- }
-
- sSocketMain=socket(AF_INET, SOCK_STREAM, 0);
- if(sSocketMain==SOCKET_ERROR)
- {
- netError();
- DestroyWindow(hWndMain);
- UnregisterClass((LPSTR)szNetworkClass, hInst);
- return(TRUE);
- }
-
- lpseServEnt=getservbyname((LPSTR)SMTP_NAME, NULL);
- if(lpseServEnt==NULL)
- {
- saMain.sin_port=htons(SMTP_PORT);
- }
- else
- {
- saMain.sin_port=lpseServEnt->s_port;
- }
-
- saMain.sin_family=AF_INET; // Address Family type Internet
- saMain.sin_addr.s_addr=0; // Bind to local host
-
- if(bind(sSocketMain, (LPSOCKADDR)&saMain,
- sizeof(saMain))==SOCKET_ERROR)
- {
- netError();
- DestroyWindow(hWndMain);
- closesocket(sSocketMain);
- UnregisterClass((LPSTR)szNetworkClass, hInst);
- return(TRUE);
- }
-
- if(listen(sSocketMain, MAXCLIENTS)==SOCKET_ERROR)
- {
- netError();
- DestroyWindow(hWndMain);
- closesocket(sSocketMain);
- UnregisterClass((LPSTR)szNetworkClass, hInst);
- return(TRUE);
- }
-
- // Make the main socket non-blocking, and set up
- // the connection message.
- if(WSAAsyncSelect(sSocketMain, hWndMain, NET_ACTIVITY,
- FD_READ | FD_WRITE | FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR)
- {
- netError();
- DestroyWindow(hWndMain);
- closesocket(sSocketMain);
- UnregisterClass((LPSTR)szNetworkClass, hInst);
- return(TRUE);
- }
-
- bDebug=TRUE;
- setsockopt(sSocketMain,
- SOL_SOCKET, SO_DEBUG, (char FAR *)&bDebug,
- sizeof(bDebug));
- setsockopt(sSocketMain,
- IPPROTO_TCP, SO_DEBUG, (char FAR *)&bDebug,
- sizeof(bDebug));
-
- // ALL sockets are accounted for with structures
- // Even the main one - to get the NetProc to work right.
- smtpAddClient(sSocketMain);
- return(FALSE);
- } /* netInit() */
-
-
- /* void netError(void);
- Purpose: To tell the user something broke.
- Given: Nothing.
- Returns: Nothing.
- Uses: netErrorTable, WSAGetLastError(), smtpError()
- */
- void netError(void)
- {
- int iError;
- int iIndex;
-
- iIndex=0;
- iError=WSAGetLastError();
- if((iError==WSAEWOULDBLOCK)||
- (iError==WSAENOTCONN) ||
- (iError==WSANO_DATA)) // Why does v1.09beta tell me this?
- return;
- while(netErrorTable[iIndex].iError!=0)
- {
- if(netErrorTable[iIndex].iError==iError)
- {
- smtpError(netErrorTable[iIndex].iResourceID);
- return;
- }
- iIndex++;
- }
- return;
- } /* netError */
-
-
- /* void netClose(void);
- Purpose: To close the network portion of WSMTPSRV
- Given: Nothing.
- Returns: Nothing.
- */
- void netClose(void)
- {
- if(hWndMain)
- {
- smtpDestroyClient(smtpClientsHead);
- smtpClientsHead=NULL;
- DestroyWindow(hWndMain);
- UnregisterClass((LPCSTR)szNetworkClass, hInst);
- hWndMain=0;
- }
- WSACleanup();
- return;
- } /* netClose */
-
-
- /* BOOL CALLBACK NetProc(HWND, UINT, WPARAM, LPARAM);
- Purpose: To handle all Windows Sockets messages.
- Given: Standard CALLBACK args.
- Returns: FALSE if we handled it.
- */
- LRESULT CALLBACK NetProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
- {
- // First thing we do is get the connection's window
- LPSMTPCLIENT lpClient;
- SOCKET sSocket;
- #ifdef USE_TITLE
- char szTitle[MAXLINE];
- #endif /* USE_TITLE */
- int iAddrSize;
- SOCKADDR_IN saPeer;
- LPSOCKADDR_IN lpsaHostAddr;
- LPHOSTENT lpheHostEnt;
- char szTime[40];
-
- if(wParam!=0) lpClient=smtpSocketToClient((SOCKET)wParam);
- else lpClient=NULL;
-
- if(lpClient) // If it isn't a Client message - ignore it
- {
- switch(Msg)
- {
- case NET_ACTIVITY:
- {
- // This is the handler for the main network window
- switch(WSAGETSELECTEVENT(lParam))
- {
- case FD_ACCEPT:
- {
- // Get a pending accept
- iAddrSize=sizeof(SOCKADDR_IN);
- sSocket=accept(sSocketMain,
- (LPSOCKADDR)&saPeer,
- (int FAR *)&iAddrSize);
- if(sSocket==INVALID_SOCKET) return(FALSE);
-
- // Allocate socket specific data
- lpClient=smtpAddClient(sSocket);
-
- if(!lpClient) return(FALSE);
-
- // Remember the connected Peer's address
- lpClient->saPeer=saPeer;
- // Get the Peer's Name asyncronously
- lpsaHostAddr=(LPSOCKADDR_IN)&(lpClient->saPeer);
-
- lpheHostEnt= gethostbyaddr((LPSTR)&(lpsaHostAddr->sin_addr.s_addr),
- 4, PF_INET);
- if(lpheHostEnt==NULL)
- { // Ah HA! No sneaking in!
- lstrcpy((LPSTR)lpClient->szPeer,
- inet_ntoa(lpsaHostAddr->sin_addr));
- }
- else
- {
- lstrcpy((LPSTR)lpClient->szPeer,
- (LPSTR)(lpheHostEnt->h_name));
- }
- smtpLog(LOG_HIGH | LOG_TIME, LOG_CONNECT_S,
- (LPSTR)lpClient->szPeer);
-
- netGetTimeAndDate((LPSTR)szTime, sizeof(szTime));
-
- /* Set the window title (for debugging) */
- #ifdef USE_TITLE
- if(iLogLevel==LOG_HIGH)
- {
- wsprintf((LPSTR)szTitle, "WSMTPD - Connect: from %s:%d",
- (LPSTR)lpClient->szPeer,
- lpClient->saPeer.sin_port);
- SetWindowText(hWndDlg, (LPSTR)szTitle);
- }
- #endif /* USE_TITLE */
-
- smtpSendMessage(lpClient, 220, MSG_I_AM_S_S,
- (LPSTR)szLocalHostName,
- (LPSTR)szTime);
-
- // Not all stacks support this yet.
- /* if(WSAAsyncGetHostByAddr(hWnd, NET_NAME,
- (LPSTR)&(lpsaHostAddr->sin_addr.s_addr),
- 4, PF_INET,
- (LPSTR)lpClient->hePeer,
- MAXGETHOSTSTRUCT) != 0)
- {
- return(FALSE);
- } /**/
- // Make sure that the name can be found
- netError();
- PostMessage(hWnd, NET_NAME, 0, WSAMAKEASYNCREPLY(0 ,1));
- return(FALSE);
- }
-
- // WinSock received something for us
- case FD_READ:
- {
- int iError;
-
- // FIFO log it
- iError=netReceiveData(lpClient);
- if(iError==0)
- { // It closed!?!
- smtpDestroyClient(lpClient);
- return(FALSE);
- }
- else if(iError==SOCKET_ERROR)
- { // Miscellaneous Error
- netError();
- return(FALSE);
- }
- // Call the server routines
- (void)smtpServer(lpClient);
- // We handled the event, return FALSE
- return(FALSE);
- }
- break; /* FD_READ */
-
- // WinSock is ready to send
- case FD_WRITE:
- { // FIFO log it
- if(netSendData(lpClient)==SOCKET_ERROR)
- {
- netError();
- }
- return(FALSE);
- }
- break;
-
- // The MAIN accepting network window was closed!!!
- case FD_CLOSE:
- { // This DOESNT work. And a good thing too..
- //smtpSendMessage(lpClient, 221, MSG_GOODBYE_S,
- // (LPSTR)szLocalHostName);
-
- /* Set the window title (for debugging) */
- #ifdef USE_TITLE
- if(iLogLevel==LOG_HIGH)
- {
- wsprintf((LPSTR)szTitle, "WSMTPD - %s disconnected from port %d",
- (LPSTR)lpClient->szPeer,
- lpClient->saPeer.sin_port);
- SetWindowText(hWndDlg, (LPSTR)szTitle);
- }
- #endif /* USE_TITLE */
-
- // Hasta la Vista, Baby
- smtpDestroyClient(lpClient);
- return(FALSE);
- }
- break;
-
- // Shouldn't get to here!!!
- default:
- {
- netError();
- return(FALSE);
- }
- }
- } /* NET_ACCEPT */
- break;
-
- // Get the peer's name - No spoofing allowed in this server!
- // gethostbyname() doesn't seem to block much anyway
- // so it's a decent compromise.
- /* case NET_NAME:
- {
- DEBUGIT("NET_NAME Event!");
- if(WSAGETASYNCERROR(lParam))
- {
- lstrcpy((LPSTR)lpClient->szPeer,
- (LPSTR)STRING_UNKNOWN);
- }
- else // We found a name!!!!
- {
- lstrcpy((LPSTR)lpClient->szPeer,
- (LPSTR)((HOSTENT*)(lpClient->hePeer))->h_name);
- }
-
- smtpLog(LOG_CONNECT_S, (LPSTR)lpClient->szPeer);
- }
- break; /**/
- } /* Msg*/
- } /* if(index) */
-
- switch(Msg)
- {
- case WM_CLOSE:
- { // A WSACleanup() here, and a WSACleanup() there....
- smtpDestroyClient(smtpClientsHead);
- smtpClientsHead=NULL;
- WSACleanup();
- } break;
-
- default:
- {
- // Something has to handle the other messages!
- return(DefWindowProc(hWnd, Msg, wParam, lParam));
- }
- }
- } /* NetProc() */
-
-
- /* int netGetTimeAndDate(LPSTR, int);
- Purpose: To format the current system time/data into a passed
- buffer.
- Doesn't formats the output to what other SMTP servers
- report - uses the ctime() call.
- Given: String buffer pointer, and size of the buffer
- Returns: TRUE if an error occurs, false otherwise
- Notes: Version 1.0 uses DOS time functions. The Windows ones
- are undocumented.
- */
- BOOL netGetTimeAndDate(LPSTR lpLine, int iLine)
- {
- struct tm tmClock;
- time_t tClock;
- LPSTR lpSysTime;
- char szTemp[256];
-
- time(&tClock);
- tmClock=*localtime(&tClock);
-
- if(!strftime(szTemp, sizeof(szTemp), "%a, %d %b %y %H:%M:%S %z",
- &tmClock))
- {
- lstrcpy((LPSTR)szTemp, (LPSTR)asctime(&tmClock));
- szTemp[lstrlen((LPSTR)szTemp)-1]='\0';
- };
-
- if(lstrlen((LPSTR)szTemp)>iLine)
- {
- szTemp[iLine]='\0';
- }
- lstrcpy(lpLine, (LPSTR)szTemp);
-
- return(FALSE);
- } /* netGetTimeAndDate() */
-
-
- /* int netSendData(int);
- Purpose: To send data in the appropriate FIFO buffer
- Sends data, and updates the pointers to what
- was actually sent.
- Given: Client index;
- Returns: Same as send()
- Notes: If smtpSendString finds stop=start, then he
- should flag the fact that the buffer WAS
- empty, and then call this routine to set up
- sending messages!!!
- */
- int netSendData(LPSMTPCLIENT lpClient)
- {
- LPSTR lpBuffer;
- LPSTR lpLine;
- int fifoStart;
- int fifoStop;
- int fifoWalker;
- int iDest;
- int iCount;
- int sSocket;
- #ifdef USE_TITLE
- char szTitle[MAXLINE];
- #endif /* USE_TITLE */
-
- sSocket = lpClient->sSocket;
-
- if(!lpClient) return(SOCKET_ERROR);
- lpLine = (LPSTR)szMainBuffer;
- /* Make things easier to deal with */
- lpBuffer=lpClient->lpOutputBuffer;
- fifoStart=lpClient->fifoOutputStart;
- fifoWalker=fifoStart;
- fifoStop=lpClient->fifoOutputStop;
-
- if(fifoStart==fifoStop)
- {
- return(0);
- }
-
- /* Keep trying to send until buffer
- is empty, or WSAEWOULDBLOCK */
- // do
- // {
- iDest=0;
- while(fifoWalker!=fifoStop)
- {
- lpLine[iDest]=lpBuffer[fifoWalker];
- fifoWalker=(fifoWalker+1)%MAXSNDBUFF;
- iDest++;
- }
-
- iCount=send(sSocket, lpLine,
- iDest, 0);
- if(iCount==SOCKET_ERROR)
- {
- return(iCount);
- }
-
- fifoWalker=(fifoStart+iCount)%MAXSNDBUFF;
- lpClient->fifoOutputStart=fifoWalker;
-
- /* Set the window title (for debugging) */
- #ifdef USE_TITLE
- if(iLogLevel==LOG_HIGH)
- {
- wsprintf((LPSTR)szTitle, "WSMTPD - Sent: %d bytes to %s:%u",
- iCount,
- (LPSTR)lpClient->szPeer,
- lpClient->saPeer.sin_port);
- SetWindowText(hWndDlg, (LPSTR)szTitle);
- }
- #endif /* USE_TITLE */
-
- // iDest -= iCount;
- // } while(iDest!=0);
-
- return(iCount);
- } /* netSendData */
-
-
- /* int netRecieveData(int);
- Purpose: To receive data from WinSock into FIFOs
- Updates the fifoStop pointer to the end of the
- new data.
- If no data is waiting, or there is no more room
- in the buffer, this routine returns like recv().
- Given: Client index.
- Returns: same as recv();
- */
- int netReceiveData(LPSMTPCLIENT lpClient)
- {
- LPSTR lpBuffer;
- LPSTR lpLine;
- int fifoStart;
- int fifoStop;
- int fifoWalker;
- int iMax;
- int iDest;
- int iCount;
- int sSocket;
- #ifdef USE_TITLE
- char szTitle[MAXLINE];
- #endif /* USE_TITLE */
-
- sSocket = lpClient->sSocket;
- lpLine = (LPSTR)szMainBuffer;
- iMax=lpClient->iInputSize;
-
- fifoStart=lpClient->fifoInputStart;
- fifoStop=lpClient->fifoInputStop;
-
- // Calculate the room we have ready
- // szMainBuffer can be a bottleneck if the Receive buffer is big
- if(fifoStop<fifoStart) iDest=min( (fifoStart-fifoStop),
- sizeof(szMainBuffer) );
- else if(fifoStart<=fifoStop) iDest=min( (iMax-fifoStop+fifoStart),
- sizeof(szMainBuffer) );
- // The min() hack was so that we don't get more data than we
- // are ready to handle.
-
- lpBuffer=lpClient->lpInputBuffer;
-
- /* There is room at the end! Copy it in! */
- /* Tell winsock to release it first, tho */
- iCount=recv(sSocket, lpLine,
- iDest, 0);
-
- /* Set the window title (for debugging) */
- #ifdef USE_TITLE
- if(iLogLevel==LOG_HIGH)
- {
- if(iCount!=SOCKET_ERROR)
- {
- wsprintf((LPSTR)szTitle, "WSMTPD - Received: %d bytes from %s:%u",
- iCount,
- (LPSTR)lpClient->szPeer,
- lpClient->saPeer.sin_port);
- SetWindowText(hWndDlg, (LPSTR)szTitle);
- }
- else
- {
- if((WSAGetLastError()!=WSAENOTCONN)&&
- (WSAGetLastError()!=WSAEINPROGRESS))
- {
- wsprintf((LPSTR)szTitle, "WSMTPD - SOCKET_ERROR #%d from %s:%u",
- WSAGetLastError(),
- (LPSTR)lpClient->szPeer,
- lpClient->saPeer.sin_port);
- SetWindowText(hWndDlg, (LPSTR)szTitle);
- }
- }
- }
- #endif /* USE_TITLE */
-
- if(iCount==SOCKET_ERROR)
- { // If something was blocking, always try again
- return(iCount);
- }
- if(iCount==0) return(iCount);
-
- iDest=0;
- fifoWalker=fifoStop;
- while(iDest<iCount)
- {
- lpBuffer[fifoWalker]=lpLine[iDest];
- fifoWalker=(fifoWalker+1)%iMax;
- iDest++;
- }
-
- lpClient->fifoInputStop=fifoWalker;
- return(iCount);
- } /* netReceiveData */
-
-
- #endif /* NET_C */
-
-