summaryrefslogtreecommitdiff
path: root/protocols/SkypeClassic/src/skypeproxy/skypeproxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/SkypeClassic/src/skypeproxy/skypeproxy.c')
-rw-r--r--protocols/SkypeClassic/src/skypeproxy/skypeproxy.c651
1 files changed, 651 insertions, 0 deletions
diff --git a/protocols/SkypeClassic/src/skypeproxy/skypeproxy.c b/protocols/SkypeClassic/src/skypeproxy/skypeproxy.c
new file mode 100644
index 0000000000..fff9c1b916
--- /dev/null
+++ b/protocols/SkypeClassic/src/skypeproxy/skypeproxy.c
@@ -0,0 +1,651 @@
+/*
+
+Purpose
+=======
+This program opens a connection on a local TCP/IP port and sends/
+receives Skype-API calls on it so that you can remote-control
+Skype over a network.
+Note, that there are currently NO SECURITY mechanisms, so don't
+use this over an untrusted network!
+
+Author
+======
+This program was written by leecher in 2005 (mailto:leecher@dose.0wnz.at)
+Please give feedback at http://forum.skype.com/viewtopic.php?t=16187
+
+Protocol
+========
+Basic protocol structure
+------------------------
+Sender and receiver have the same protocol:
+
+ [(UINT)Length of message][(char[])Message]
+
+The Length is so that you can malloc() enough space for the data buffer
+to receive the next message.
+
+A special case is, if the [Length of message] is 0. In this case the
+client tells the server that he wants to switch to command mode.
+
+Command mode
+------------
+The server expects
+
+ [(char)Command]
+
+next. Currently the following commands are supported:
+
+ CAPABILITIES - returns the Server's capabilities
+ AUTHENTICATE - Starts the authentification process
+
+CAPABILITIES
+------------
+The server returns
+
+ [(char)Capabilities]
+
+where this currently can be the following:
+
+ USE_AUTHENTICATION - The server supports and requires authentication
+
+AUTHENTICATE
+------------
+The server returns
+
+ [(char)0x01]
+
+if authentication is supported AND needed (skypeproxy started with -k switch) or
+
+ [(char)0x00]
+
+if this is not the case.
+If 0x01 was returned the server next expects a normal message
+(see "Basic protocol structure) containing the password.
+If the authentication was successful, the server replies with
+
+ [(char)0x01]
+
+otherwise with
+
+ [(char)0x00]
+
+PLEASE NOTE THAT THE AUTHENTICATION CURRENTLY IS PLAIN TEXT. SO DON'T
+USE THIS PROGRAM OVER AN UNTRUSTED NETWORK, OTHERWISE THERE MAY BE THE
+POSSIBILITY THAT SOMEONE SNIFFS YOUR PASSWORD!
+
+Code example
+------------
+
+SOCKET MySocket;
+
+int SendPacket(char *szSkypeMessage) {
+ unsigned int length=strlen(szSkypeMsg);
+
+ if (send(MySocket, (char *)&length, sizeof(length), 0)==SOCKET_ERROR ||
+ send(MySocket, szSkypeMsg, length, 0)==SOCKET_ERROR)
+ return -1;
+ return 0;
+}
+
+// don't forget to free() the return value on my Heap!!
+char *ReceivePacket(void) {
+ unsigned int lenght, received;
+ char *buf;
+
+ if ((received=recv(MySocket, (char *)&length, sizeof(length), 0))==SOCKET_ERROR ||
+ received==0)
+ return NULL;
+ if (!(buf=calloc(1, length+1))) return NULL;
+ if (recv(MySocket, buf, length, 0)==SOCKET_ERROR) {
+ free(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+
+License
+=======
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+History
+========
+V1.0alpha - First preview release
+V1.0 - Implemented killing & restarting Skype process when it dies
+ - BUGFIX: SendMessage() is a blocking call, if Skype hangs our app hangs too -> Fixed
+ - Added command line parsing.
+ - Renamed from Skype2Socket to skypeproxy
+ - Added authentication feature.
+*/
+
+#include <stdio.h>
+#include <process.h>
+#include <windows.h>
+#include <signal.h>
+#include "skypeproxy.h"
+
+UINT ControlAPIAttach, ControlAPIDiscover;
+HWND hSkypeWnd=NULL, hWnd;
+HANDLE SkypeReady, ServerThreadBye;
+LONG AttachStatus=-1;
+int exitcode=EXIT_SUCCESS;
+char skype_path[MAX_PATH], *password=NULL;
+BYTE WatchDog=1;
+BOOL WatchDogRunning=FALSE, Authenticated=FALSE;
+SOCKET ListenSocket, AcceptSocket;
+
+
+void bail_out(int i) {
+ OUTPUT("Got termination signal, bailing out.");
+ if (i==1) exitcode=EXIT_FAILURE;
+ PostMessage(hWnd, WM_QUIT, 0, 0);
+}
+
+BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam ) {
+ DWORD dwID ;
+
+ GetWindowThreadProcessId(hwnd, &dwID) ;
+ if(dwID == (DWORD)lParam)
+ PostMessage(hwnd, WM_CLOSE, 0, 0) ; // May you be so kind to quit, please?
+
+ return TRUE ;
+}
+
+/* ConnectToSkypeAPI
+ *
+ * Purpose: Establish a connection to the Skype API
+ * Params : ForceRestart - Kill Skype if it's running before restarting
+ * Returns: 0 - Connecting succeeded
+ * -1 - Something went wrong
+ */
+void ConnectToSkypeAPI(void *ForceRestart) {
+ BOOL SkypeLaunched=FALSE;
+ int counter=0, i, j;
+ char *args[5];
+ char *SkypeOptions[]={"/notray", "/nosplash", "/minimized"};
+ char *szFuncName="ConnectToSkypeAPI";
+
+ ResetEvent(SkypeReady);
+ AttachStatus=-1;
+ if ((BOOL)ForceRestart) {
+ HANDLE hProc;
+ DWORD dwPID=0;
+
+ if (!hSkypeWnd) {
+ OUTPUT("I can't kill Skype, as I don't even have its window handle!");
+ return;
+ }
+ GetWindowThreadProcessId(hSkypeWnd, &dwPID);
+ LOG(("%s: Shutting down Skype as it was not behaving the way it should...", szFuncName));
+ if (hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, dwPID)) {
+
+ // Try to shutdown Skype the nice way by asking it to close
+ EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID);
+
+ if(WaitForSingleObject(hProc, 10000)!=WAIT_OBJECT_0) {
+ // Try it the hard way by killing it
+ LOG(("%s: I tried it the nice way, but you were not listening! Now DIIIIEEE!", szFuncName));
+ if (!TerminateProcess(hProc,0)) {
+ OUTPUT("Argh, process refused to die, it's too mighty for me, I've given up");
+ CloseHandle(hProc);
+ return;
+ }
+ LOG(("%s: Process killed! >:)", szFuncName));
+ }
+ CloseHandle(hProc);
+ }
+ }
+ do {
+ /* To initiate communication, Client should broadcast windows message
+ ('SkypeControlAPIDiscover') to all windows in the system, specifying its own
+ window handle in wParam parameter.
+ */
+ LOG(("%s: Sending discover message..", szFuncName));
+ SendMessageTimeout(HWND_BROADCAST, ControlAPIDiscover, (WPARAM)hWnd, 0, SMTO_ABORTIFHUNG, 3000, NULL);
+ LOG(("%s: Discover message sent, waiting for Skype to become ready..", szFuncName));
+
+ /* In response, Skype responds with
+ message 'SkypeControlAPIAttach' to the handle specified, and indicates
+ connection status
+ SkypeReady is set if there is an answer by Skype other than API_AVAILABLE.
+ If there is no answer after 3 seconds, launch Skype as it's propably
+ not running.
+ */
+ if (WaitForSingleObject(SkypeReady, 3000)==WAIT_TIMEOUT &&
+ AttachStatus!=SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION)
+ {
+ if (hWnd==NULL) {
+ LOG(("%s: hWnd of SkypeDispatchWindow not yet set..", szFuncName));
+ continue;
+ }
+ if (!SkypeLaunched && skype_path) {
+ LOG(("%s: Starting Skype, as it's not running", szFuncName));
+ args[0]=skype_path;
+ j=1;
+ for (i=0; i<3; i++) {
+ args[j]=SkypeOptions[i];
+ LOG(("%s: Using Skype parameter: ", szFuncName, args[j]));
+ j++;
+ }
+ args[j]=NULL;
+ _spawnv(_P_NOWAIT, skype_path, args);
+ ResetEvent(SkypeReady);
+ SkypeLaunched=TRUE;
+ LOG(("%s: Skype process started.", szFuncName));
+ // Skype launching iniciated, keep sending Discover messages until it responds.
+ continue;
+ } else {
+ LOG(("%s: Check if Skype was launchable..", szFuncName));
+ if (!skype_path) {
+ OUTPUT("There was no correct path for Skype application");
+ bail_out(1);
+ return;
+ }
+ LOG("%s: Trying to attach: #%d", szFuncName, counter));
+ counter++;
+ if (counter==5) {
+ OUTPUT("ERROR: Skype not running / too old / working!");
+ bail_out(1);
+ return;
+ }
+ }
+ }
+ LOG(("%s: Attachstatus %d", szFuncName, AttachStatus));
+ } while (AttachStatus==SKYPECONTROLAPI_ATTACH_API_AVAILABLE || AttachStatus==-1);
+
+ while (AttachStatus==SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION) Sleep(1000);
+ LOG(("%s: Attachstatus %d", szFuncName, AttachStatus));
+ if (AttachStatus!=SKYPECONTROLAPI_ATTACH_SUCCESS) {
+ switch(AttachStatus) {
+ case SKYPECONTROLAPI_ATTACH_REFUSED:
+ OUTPUT("Skype refused the connection :(");
+ break;
+ case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE:
+ OUTPUT("The Skype API is not available");
+ break;
+ default:
+ LOG(("%s: ERROR: AttachStatus: %d", szFuncName, AttachStatus));
+ OUTPUT("Wheee, Skype won't let me use the API. :(");
+ }
+ bail_out(1);
+ return;
+ }
+ OUTPUT("Attached to Skype successfully.");
+ if (!WatchDogRunning)
+ if (_beginthread(WatchDogTimer, 0, NULL)==-1) {
+ OUTPUT("Cannot start Watchdog.");
+ bail_out(1);
+ }
+ return;
+}
+
+void SkypeSend(char *szMsg) {
+ COPYDATASTRUCT CopyData;
+ int count=0;
+
+ if (!hSkypeWnd) {
+ LOG(("SkypeSend: DAMN! No Skype window handle! :("));
+ return;
+ }
+ if (strcmp(szMsg, "PING")) {LOG(("> %s", szMsg));}
+ CopyData.dwData=0;
+ CopyData.lpData=szMsg;
+ CopyData.cbData=strlen(szMsg)+1;
+ while (!SendMessageTimeout(hSkypeWnd, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&CopyData, SMTO_ABORTIFHUNG, 3000, NULL)) {
+ count++;
+ LOG(("SkypeSend: failed, try #%d", count));
+ if (count==5) {
+ OUTPUT("Sending message to Skype failed too often.");
+ OUTPUT("Skype may have died unexpectedly, I will try to restart it.");
+ ConnectToSkypeAPI((void *)TRUE);
+ OUTPUT("Restart complete. Trying to deliver message one more time.");
+ if (!SendMessageTimeout(hSkypeWnd, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&CopyData, SMTO_ABORTIFHUNG, 3000, NULL)) {
+ OUTPUT("It still failed. Skype seems to be completely f*cked up. I've given up. Bye..");
+ bail_out(1);
+ break;
+ } else {
+ OUTPUT("Now it worked! :)");
+ break;
+ }
+ }
+ Sleep(1000);
+ }
+}
+
+void ServerThread(char *dummy) {
+ unsigned int length, received;
+ char *buf, command, reply;
+
+ LOG(("ServerThread started"));
+ AcceptSocket=INVALID_SOCKET;
+ while( AcceptSocket == INVALID_SOCKET) {
+ if ((AcceptSocket = accept( ListenSocket, NULL, NULL ))==INVALID_SOCKET) {
+ LOG(("ServerThread: Byebye..."));
+ SetEvent(ServerThreadBye);
+ bail_out(1);
+ return;
+ }
+ OUTPUT("Connection by client");
+ while(1) {
+ if ((received=recv(AcceptSocket, (char *)&length, sizeof(length), 0))==SOCKET_ERROR ||
+ received==0)
+ {
+ OUTPUT("Connection was closed by client. See ya soon! :)");
+ break;
+ }
+ // Command mode
+ if (length==0) {
+ reply=0;
+ if (recv(AcceptSocket, (char *)&command, 1, 0)==SOCKET_ERROR) {
+ OUTPUT("Connection to client was lost.");
+ break;
+ }
+#ifdef USE_AUTHENTICATION
+ if (command==AUTHENTICATE)
+ if (password) reply=0x01; // Ok, go ahead
+ else command=0;
+#endif
+ if (command==CAPABILITIES)
+ reply=password?USE_AUTHENTICATION:0;
+
+ if (send(AcceptSocket, (char *)&reply, 1, 0)==SOCKET_ERROR) {
+ OUTPUT("Connection to client was lost.");
+ break;
+ }
+ continue;
+ }
+ // Normal Skype API-call
+ if (!(buf=calloc(1, length+1))) {
+ OUTPUT("Out of memory error while allocating buffer space.");
+ break;
+ }
+ if (recv(AcceptSocket, buf, length, 0)==SOCKET_ERROR) {
+ OUTPUT("Connection to client was lost.");
+ free(buf);
+ break;
+ }
+ switch (command) {
+#ifdef USE_AUTHENTICATION
+ case 0x01: // Compare hash
+ if (password && !strcmp(password, buf)) Authenticated=TRUE;
+ else Authenticated=FALSE;
+ if (Authenticated) {
+ OUTPUT("User authenticated succesfully.");
+ reply=1;
+ } else {
+ OUTPUT("User authentication failed!! (Intruder?)");
+ reply=0;
+ }
+ if (send(AcceptSocket, (char *)&reply, 1, 0)==SOCKET_ERROR) {
+ OUTPUT("Connection to client was lost.");
+ break;
+ }
+ command=0;
+ break;
+#endif
+ default:
+#ifdef USE_AUTHENTICATION
+ if (password && !Authenticated) break;
+#endif
+ SkypeSend(buf);
+ }
+ command=0;
+ free(buf);
+ }
+ AcceptSocket=INVALID_SOCKET;
+#ifdef USE_AUTHENTICATION
+ Authenticated=FALSE;
+#endif
+ }
+}
+
+
+void WatchDogTimer(char *dummy) {
+ LOG(("WatchDogTimer started"));
+ WatchDogRunning=TRUE;
+ while (1) {
+ Sleep(PING_INTERVAL);
+ if (!WatchDog) {
+ OUTPUT("Ouch.. It seems that Skype has died unexpectedly. Trying to restart.");
+ ConnectToSkypeAPI((void *)TRUE);
+ }
+ WatchDog=0;
+ SkypeSend("PING");
+ }
+}
+
+LONG APIENTRY WndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
+{
+ PCOPYDATASTRUCT CopyData;
+ char *szSkypeMsg=NULL;
+
+ switch (message)
+ {
+ case WM_COPYDATA:
+// LOG("WM_COPYDATA", "start");
+ if(hSkypeWnd==(HWND)wParam) {
+ CopyData=(PCOPYDATASTRUCT)lParam;
+ szSkypeMsg=strdup(CopyData->lpData);
+ ReplyMessage(1);
+ if (!strcmp(szSkypeMsg, "PONG")) {
+ WatchDog=1;
+ break;
+ } // Hide PING-PONG
+ LOG(("< %s", szSkypeMsg));
+ if (!strcmp(szSkypeMsg, "USERSTATUS LOGGEDOUT")) {
+ OUTPUT("Skype shut down gracefully. I'll leave too, bye.. :)");
+ bail_out(1);
+ }
+#ifdef USE_AUTHENTICATION
+ if (password && !Authenticated) break;
+#endif
+ if (AcceptSocket!=INVALID_SOCKET) {
+ unsigned int length=strlen(szSkypeMsg);
+
+ if (send(AcceptSocket, (char *)&length, sizeof(length), 0)==SOCKET_ERROR ||
+ send(AcceptSocket, szSkypeMsg, length, 0)==SOCKET_ERROR)
+ OUTPUT("Cannot send to client :(");
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ default:
+ if(message==ControlAPIAttach) {
+ // Skype responds with Attach to the discover-message
+ AttachStatus=lParam;
+ if (AttachStatus==SKYPECONTROLAPI_ATTACH_SUCCESS)
+ hSkypeWnd=(HWND)wParam; // Skype gave us the communication window handle
+ if (AttachStatus!=SKYPECONTROLAPI_ATTACH_API_AVAILABLE)
+ SetEvent(SkypeReady);
+ break;
+ }
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+// LOG("WM_COPYDATA", "exit");
+ if (szSkypeMsg) free(szSkypeMsg);
+ return 1;
+}
+
+
+void TellError(DWORD err) {
+ LPVOID lpMsgBuf;
+
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
+ MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
+ LocalFree( lpMsgBuf );
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ DWORD Buffsize;
+ HKEY MyKey;
+ BOOL SkypeInstalled=TRUE;
+ MSG Message;
+ WNDCLASS WndClass;
+ SOCKADDR_IN service;
+ WSADATA wsaData;
+ int ExitCode=STILL_ACTIVE;
+ unsigned short BindPort=1401;
+ char BindIP[16]="0.0.0.0";
+
+ printf("Skypeproxy V1.0, by leecher 2005 <leecher@dose.0wnz.at>\n\n");
+
+ if (argc>1) {
+ int i;
+
+ if (!stricmp(argv[1], "-h") || !stricmp(argv[1], "--help") || !stricmp(argv[1], "/?")) {
+ printf("Usage: %s [-i BindIP] [-p BindPort]", argv[0]);
+#ifdef USE_AUTHENTICATION
+ printf(" [-k Password]");
+#endif
+ printf("\n\n");
+ return EXIT_SUCCESS;
+ }
+ for (i=0;i<argc;i++) {
+ if (!stricmp(argv[i], "-i") && argc>i+1)
+ strncpy(BindIP, argv[i+1], sizeof(BindIP));
+ if (!stricmp(argv[i], "-p") && argc>i+1)
+ if (!(BindPort=atoi(argv[i+1]))) {
+ OUTPUT("ERROR: Cannot convert port to int. bye..");
+ return EXIT_FAILURE;
+ }
+#ifdef USE_AUTHENTICATION
+ if (!stricmp(argv[i], "-k") && argc>i+1)
+ password=strdup(argv[i+1]);
+#endif
+ }
+ }
+
+ if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Skype\\Phone", 0, KEY_READ, &MyKey)!=ERROR_SUCCESS ||
+ RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Skype\\Phone", 0, KEY_READ, &MyKey)!=ERROR_SUCCESS)
+ SkypeInstalled=FALSE;
+ Buffsize=sizeof(skype_path);
+ if (SkypeInstalled==FALSE ||
+ RegQueryValueEx(MyKey, "SkypePath", NULL, NULL, skype_path, &Buffsize)!=ERROR_SUCCESS) {
+ OUTPUT("Skype was not found on this machine :(");
+ RegCloseKey(MyKey);
+ skype_path[0]=0;
+ return EXIT_FAILURE;
+ }
+ RegCloseKey(MyKey);
+
+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR) {
+ OUTPUT("Error at loading windows sockets.");
+ return EXIT_FAILURE;
+ }
+
+ if ((ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
+ printf("* Error at creating socket(): Error %d", WSAGetLastError());
+ return EXIT_FAILURE;
+ }
+
+ service.sin_family = AF_INET;
+ service.sin_addr.s_addr = inet_addr(BindIP);
+ service.sin_port = htons(BindPort);
+
+ printf("* Binding to interface %s, Port %d..", BindIP, BindPort);
+ if (bind( ListenSocket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR ||
+ listen( ListenSocket, 1 ) == SOCKET_ERROR)
+ {
+ OUTPUT("Failed.");
+ closesocket(ListenSocket);
+ return EXIT_FAILURE;
+ }
+ printf("OK\n");
+
+
+ if (!(ControlAPIAttach=RegisterWindowMessage("SkypeControlAPIAttach")) ||
+ !(ControlAPIDiscover=RegisterWindowMessage("SkypeControlAPIDiscover"))) {
+ OUTPUT("Cannot register Windows message.");
+ closesocket(ListenSocket);
+ return EXIT_FAILURE;
+ }
+
+ // Create window class
+ hSkypeWnd=NULL;
+ WndClass.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
+ WndClass.lpfnWndProc = (WNDPROC)WndProc;
+ WndClass.cbClsExtra = 0;
+ WndClass.cbWndExtra = 0;
+ WndClass.hInstance = NULL;
+ WndClass.hIcon = NULL;
+ WndClass.hCursor = NULL;
+ WndClass.hbrBackground = NULL;
+ WndClass.lpszMenuName = NULL;
+ WndClass.lpszClassName = "SkypeApiDispatchWindow";
+ RegisterClass(&WndClass);
+ // Do not check the retval of RegisterClass, because on non-unicode
+ // win98 it will fail, as it is a stub that returns false() there
+
+ // Create main window
+ hWnd=CreateWindowEx( WS_EX_APPWINDOW|WS_EX_WINDOWEDGE,
+ "SkypeApiDispatchWindow", "", WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT, 128, 128, NULL, 0, (HINSTANCE)WndClass.hInstance, 0);
+
+ if (!hWnd) {
+ OUTPUT("Cannot create window.");
+ TellError(GetLastError());
+ closesocket(ListenSocket);
+ CloseHandle(WndClass.hInstance);
+ return EXIT_FAILURE;
+ }
+ ShowWindow(hWnd, 0);
+ UpdateWindow(hWnd);
+
+ if (!(SkypeReady=CreateEvent(NULL, TRUE, FALSE, NULL)) ||
+ !(ServerThreadBye=CreateEvent(NULL, TRUE, FALSE, NULL))) {
+ OUTPUT("Unable to create Mutex!");
+ closesocket(ListenSocket);
+ CloseHandle(WndClass.hInstance);
+ return EXIT_FAILURE;
+ }
+
+ if (_beginthread(ConnectToSkypeAPI, 0, (void *)FALSE)==-1 ||
+ _beginthread(ServerThread, 0, NULL)==-1) {
+ OUTPUT("Cannot create thread. Bye..");
+ closesocket(ListenSocket);
+ CloseHandle(WndClass.hInstance);
+ CloseHandle(SkypeReady);
+ return EXIT_FAILURE;
+ }
+
+ signal(SIGINT, &bail_out);
+ LOG(("Startup: Messagepump started.\nPress CTRL+C to terminate\n"));
+
+ while (GetMessage(&Message, hWnd, 0, 0))
+ {
+ TranslateMessage(&Message);
+ DispatchMessage(&Message);
+ }
+
+ LOG(("Shutdown: Messagepump stopped"));
+
+ if (password) free(password);
+ if (AcceptSocket != INVALID_SOCKET) closesocket(AcceptSocket);
+ closesocket(ListenSocket);
+ LOG(("Shutdown: Waiting for serverthread to quit..."));
+ if (WaitForSingleObject(ServerThreadBye, 3000)==WAIT_TIMEOUT)
+ {OUTPUT("Serverthread didn't terminate correctly, shutting down anyway...");}
+ else
+ {LOG(("ServerThread terminated"));}
+ CloseHandle(WndClass.hInstance);
+ CloseHandle(SkypeReady);
+ return exitcode;
+} \ No newline at end of file