/* * Skype plugin for libpurple/Pidgin/Adium * Written by: Eion Robb * * This plugin uses the Skype API to show your contacts in libpurple, and send/receive * chat messages. * It requires the Skype program to be running. * * 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 3 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, see . */ #ifndef INCLUDED_LIBSKYPE_C # error "Don't compile this file directly. Just compile libskype.c instead." #endif #include #include #include #define SKYPE_WIN32_CLASS_NAME "Skype-libpurple-Joiner" static LRESULT APIENTRY Skype_WindowProc(HWND hWindow, UINT uiMessage, WPARAM uiParam, LPARAM ulParam); static void win32_message_loop(void); HINSTANCE hInit_ProcessHandle = NULL; static UINT uiGlobal_MsgID_SkypeControlAPIAttach = 0; static UINT uiGlobal_MsgID_SkypeControlAPIDiscover = 0; static HWND hInit_MainWindowHandle = NULL; static HWND hGlobal_SkypeAPIWindowHandle = NULL; HANDLE hEvent = NULL; static gboolean skype_connect() { int i = 0; PDWORD_PTR sendMessageResult = NULL; if (!uiGlobal_MsgID_SkypeControlAPIAttach) uiGlobal_MsgID_SkypeControlAPIAttach = RegisterWindowMessage("SkypeControlAPIAttach"); if (!uiGlobal_MsgID_SkypeControlAPIDiscover) uiGlobal_MsgID_SkypeControlAPIDiscover = RegisterWindowMessage("SkypeControlAPIDiscover"); if (!hInit_ProcessHandle) hInit_ProcessHandle = (HINSTANCE)OpenProcess( PROCESS_DUP_HANDLE, FALSE, GetCurrentProcessId()); skype_debug_info("skype_win32", "ProcessId %d\n", GetCurrentProcessId()); skype_debug_info("skype_win32", "hInit_ProcessHandle %d\n", hInit_ProcessHandle); g_thread_create((GThreadFunc)win32_message_loop, NULL, FALSE, NULL); while(hInit_MainWindowHandle == NULL) { Sleep(10); } skype_debug_info("skype_win32", "hInit_MainWindowHandle %d\n", hInit_MainWindowHandle); skype_debug_info("skype_win32", "Sending broadcast message\n"); SendMessageTimeout( HWND_BROADCAST, uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM)hInit_MainWindowHandle, 0, SMTO_NORMAL, 1000, sendMessageResult); skype_debug_info("skype_win32", "Broadcast message sent\n"); while(hGlobal_SkypeAPIWindowHandle == NULL && i < 100) { i++; Sleep(10); } if (hGlobal_SkypeAPIWindowHandle == NULL) return FALSE; return TRUE; } static void win32_message_loop(void) { MSG msg; WNDCLASS oWindowClass; int classRegistration; static gboolean message_loop_started = FALSE; if (message_loop_started) return; message_loop_started = TRUE; oWindowClass.style = CS_HREDRAW|CS_VREDRAW; oWindowClass.lpfnWndProc = (WNDPROC)&Skype_WindowProc; oWindowClass.cbClsExtra = 0; oWindowClass.cbWndExtra = 0; oWindowClass.hInstance = hInit_ProcessHandle; oWindowClass.hIcon = NULL; oWindowClass.hCursor = NULL; oWindowClass.hbrBackground = NULL; oWindowClass.lpszMenuName = NULL; oWindowClass.lpszClassName = SKYPE_WIN32_CLASS_NAME; classRegistration = RegisterClass(&oWindowClass); hInit_MainWindowHandle = CreateWindow(SKYPE_WIN32_CLASS_NAME, SKYPE_WIN32_CLASS_NAME, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, hInit_ProcessHandle, NULL); ShowWindow(hInit_MainWindowHandle, SW_HIDE); UpdateWindow(hInit_MainWindowHandle); while (GetMessage(&msg, NULL, 0, 0) != 0) { TranslateMessage(&msg); DispatchMessage(&msg); } skype_debug_info("skype_win32", "Finished message loop\n"); DestroyWindow(hInit_MainWindowHandle); hInit_MainWindowHandle = NULL; message_loop_started = FALSE; } static void skype_disconnect() { UnregisterClass(SKYPE_WIN32_CLASS_NAME, hInit_ProcessHandle); CloseHandle(hInit_ProcessHandle); hInit_ProcessHandle = NULL; if (hInit_MainWindowHandle != NULL) { //tell win32_message_loop() thread to die gracefully PostMessage(hInit_MainWindowHandle, WM_QUIT, 0, 0); } } static void send_message(const char* message) { int message_num; char *error_return; COPYDATASTRUCT oCopyData; oCopyData.dwData = 0; oCopyData.lpData = (void *)message; oCopyData.cbData = strlen(message) + 1; if (SendMessage( hGlobal_SkypeAPIWindowHandle, WM_COPYDATA, (WPARAM)hInit_MainWindowHandle, (LPARAM)&oCopyData) == FALSE) { hGlobal_SkypeAPIWindowHandle = NULL; //There was an error if (message[0] == '#') { //And we're expecting a response sscanf(message, "#%d ", &message_num); error_return = g_strdup_printf("#%d ERROR WIN32", message_num); g_thread_create((GThreadFunc)skype_message_received, (void *)error_return, FALSE, NULL); } } } static LRESULT CALLBACK Skype_WindowProc(HWND hWindow, UINT uiMessage, WPARAM uiParam, LPARAM ulParam) { if(uiMessage == WM_COPYDATA && hGlobal_SkypeAPIWindowHandle == (HWND)uiParam) { PCOPYDATASTRUCT poCopyData = (PCOPYDATASTRUCT)ulParam; skype_message_received(g_strdup(poCopyData->lpData)); return 1; } else if (uiMessage == uiGlobal_MsgID_SkypeControlAPIAttach) { skype_debug_info("skype_win32", "Attached process %d %d\n", uiParam, ulParam); if (ulParam == 0) { skype_debug_info("skype_win32", "Attach success\n"); hGlobal_SkypeAPIWindowHandle = (HWND)uiParam; //TODO send a message asking what the skype username is, to work with multiple skypes } else if (ulParam == 1) skype_debug_info("skype_win32", "Pending auth\n"); else if (ulParam == 2) skype_debug_info("skype_win32", "Refused\n"); else if (ulParam == 3) skype_debug_info("skype_win32", "Not ready\n"); else if (ulParam == 0x8001) skype_debug_info("skype_win32", "Skype became ready\n"); return 1; } return DefWindowProc(hWindow, uiMessage, uiParam, ulParam); } static void hide_skype() { //don't need to since SILENT_MODE ON works return; } static gboolean exec_skype() { #ifdef INSTANTBIRD return FALSE; #else DWORD size = 0; gchar *path, *pathtemp; HKEY regkey; gboolean success = FALSE; //HKCU\Software\Skype\Phone\SkypePath or HKLM\Software\Skype\Phone\SkypePath RegOpenKey(HKEY_CURRENT_USER, "Software\\Skype\\Phone", ®key); RegQueryValueEx(regkey, "SkypePath", NULL, NULL, NULL, &size); if (size != 0) { path = g_new(gchar, size); RegQueryValueEx(regkey, "SkypePath", NULL, NULL, (LPBYTE)path, &size); } else { RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Skype\\Phone", ®key); RegQueryValueEx(regkey, "SkypePath", NULL, NULL, NULL, &size); if (size != 0) { path = g_new(gchar, size); RegQueryValueEx(regkey, "Software\\Skype\\Phone\\SkypePath", NULL, NULL, (LPBYTE)path, &size); } else if (g_file_test("..\\Skype.Portable\\skype-start.exe", G_FILE_TEST_EXISTS)) { path = g_strdup("..\\Skype.Portable\\skype-start.exe"); } else { path = g_strdup("C:\\Program Files\\Skype\\Phone\\Skype.exe"); } } pathtemp = g_strconcat("\"", path, "\" /nosplash /minimized", NULL); skype_debug_info("skype_win32", "Path to Skype: %s\n", pathtemp); g_free(path); success = g_spawn_command_line_async(pathtemp, NULL); g_free(pathtemp); return success; #endif } static gboolean is_skype_running() { #ifdef _TLHELP32_H HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); HANDLE temp = NULL; PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); Process32First(snapshot, &entry); do { if (g_str_equal("Skype.exe", entry.szExeFile)) { temp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); CloseHandle(snapshot); return TRUE; } } while (Process32Next(snapshot, &entry)); CloseHandle(snapshot); #endif return FALSE; }