/* * 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 "skype_events.c" static gboolean skype_handle_received_message(char *message); static void skype_message_received(char *message); static gboolean skype_connect(); static void skype_disconnect(); static void send_message(const char* message); static void hide_skype(); static gboolean exec_skype(); gpointer send_messages_thread_func(gpointer data); void skype_send_message_nowait(char *message, ...); char *skype_send_message(char *message, ...); // Sort through the mess of different OS's to get the right proto #ifndef SKYPENET # ifdef _WIN32 # include "skype_messaging_win32.c" # else /*if !win32 */ # ifdef __APPLE__ # include "skype_messaging_carbon.c" # else /*if !apple */ # ifndef SKYPE_DBUS # include "skype_messaging_x11.c" # else # include "skype_messaging_dbus.c" # endif /* !x11 */ # endif /* !apple */ # endif /* win32 */ #else /* skypenet */ # include "skype_messaging_network.c" #endif /*typedef struct { gpointer sender; gpointer body; int time; gpointer chatname; } SkypeMessage;*/ static GHashTable *message_queue = NULL; static GStaticMutex mutex = G_STATIC_MUTEX_INIT; static GCond *condition = NULL; #ifdef _WIN32 //these two #defines override g_static_mutex_lock and // g_static_mutex_unlock so as to remove "strict-aliasing" // compiler warnings #define g_static_mutex_get_mutex2(mutex) \ g_static_mutex_get_mutex ((GMutex **)(void*)mutex) #define g_static_mutex_lock2(mutex) \ g_mutex_lock (g_static_mutex_get_mutex2 (mutex)) #define g_static_mutex_unlock2(mutex) \ g_mutex_unlock (g_static_mutex_get_mutex2 (mutex)) #else #define g_static_mutex_get_mutex2 g_static_mutex_get_mutex #define g_static_mutex_lock2 g_static_mutex_lock #define g_static_mutex_unlock2 g_static_mutex_unlock #endif static void skype_message_received(char *orig_message) { guint request_number; guint *key; int string_pos; char *message; if (orig_message == NULL || strlen(orig_message) == 0) return; message = g_strdup(orig_message); g_free(orig_message); skype_debug_info("skype", "Received: %s\n", message); if(message[0] == '#') { //It's a reply from a call we've made - update the hash table sscanf(message, "#%u %n", &request_number, &string_pos); key = g_new(guint, 1); *key = request_number; g_static_mutex_lock2(&mutex); g_hash_table_insert(message_queue, key, g_strdup(&message[string_pos])); g_cond_broadcast(condition); g_static_mutex_unlock2(&mutex); g_free(message); } else { purple_timeout_add(1, (GSourceFunc)skype_handle_received_message, (gpointer)message); } } static GThread *send_messages_thread = NULL; static gboolean send_thread_state = FALSE; static GAsyncQueue *send_messages_queue = NULL; gpointer send_messages_thread_func(gpointer data) { gchar *message; send_thread_state = TRUE; while (send_thread_state) { //read from async queue message = g_async_queue_pop(send_messages_queue); //send the message send_message(message); g_free(message); } g_async_queue_unref(send_messages_queue); return NULL; } void skype_send_message_nowait(char *message_format, ...) { va_list args; char* message; va_start(args, message_format); message = g_strdup_vprintf(message_format, args); va_end(args); skype_debug_info("skype", "Sending: '%s'\n", message); if (send_messages_queue == NULL) send_messages_queue = g_async_queue_new(); if (send_messages_thread == NULL) { send_messages_thread = g_thread_create(send_messages_thread_func, NULL, FALSE, NULL); } g_async_queue_push(send_messages_queue, message); } char *skype_send_message(char *message_format, ...) { static guint next_message_num = 0; guint cur_message_num; char *message; char *return_msg; va_list args; #if __APPLE__ || _WIN32 || __FreeBSD__ guint timeout = 0; #else gboolean condition_result; GTimeVal endtime = {0,0}; #endif va_start(args, message_format); message = g_strdup_vprintf(message_format, args); va_end(args); if (!message_queue) message_queue = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL); g_static_mutex_lock2(&mutex); if (!condition) condition = g_cond_new(); cur_message_num = next_message_num++; if (next_message_num == G_MAXUINT) next_message_num = 0; g_static_mutex_unlock2(&mutex); //Send message asynchronously skype_send_message_nowait("#%u %s", cur_message_num, message); g_free(message); g_static_mutex_lock2(&mutex); //Wait for a response while(g_hash_table_lookup(message_queue, &cur_message_num) == NULL) { g_static_mutex_unlock2(&mutex); g_thread_yield(); #ifdef __APPLE__ RunCurrentEventLoop(kEventDurationMillisecond); g_static_mutex_lock2(&mutex); if (timeout++ == 10000) #else #ifdef _WIN32 Sleep(1); g_static_mutex_lock2(&mutex); if (timeout++ == 10000) #else #ifdef __FreeBSD__ usleep(1000); g_static_mutex_lock2(&mutex); if (timeout++ == 10000) #else //wait for message for a maximum of 10 seconds g_get_current_time(&endtime); g_time_val_add(&endtime, 10 * G_USEC_PER_SEC); g_static_mutex_lock2(&mutex); condition_result = g_cond_timed_wait(condition, g_static_mutex_get_mutex2(&mutex), &endtime); if(!condition_result) #endif #endif #endif { //we timed out while waiting g_hash_table_remove(message_queue, &cur_message_num); g_static_mutex_unlock2(&mutex); return g_strdup(""); } } return_msg = (char *)g_hash_table_lookup(message_queue, &cur_message_num); g_hash_table_remove(message_queue, &cur_message_num); g_static_mutex_unlock2(&mutex); if (strncmp(return_msg, "ERROR", 5) == 0) { g_free(return_msg); return g_strdup(""); } return return_msg; }