/* * 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 . */ #include #include typedef struct SkypeDelegate { // Required member CFStringRef clientApplicationName; // Optional members, can be NULL void (*SkypeNotificationReceived)(CFStringRef aNotificationString); void (*SkypeAttachResponse)(unsigned int aAttachResponseCode); // 0 - failed, 1 - success void (*SkypeBecameAvailable)(CFPropertyListRef aNotification); void (*SkypeBecameUnavailable)(CFPropertyListRef aNotification); } SkypeDelegate; static SkypeDelegate *delegate = NULL; static int isavailable = 0; static int client_id = 0; char * CFStringToCString(CFStringRef input) { if (input == NULL) return NULL; int strlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(input), kCFStringEncodingUTF8); char *output = NewPtr(strlen+1); CFStringGetCString(input, output, strlen+1, kCFStringEncodingUTF8); return output; } int CFNumberToCInt(CFNumberRef input) { if (input == NULL) return 0; int output; CFNumberGetValue(input, kCFNumberIntType, &output); return output; } void availabilityUpdateCallback( CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(userInfo, CFSTR("SKYPE_API_AVAILABILITY")); isavailable = CFNumberToCInt(number); } void debugCallback( CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { int i = 0; printf("Debug callback: %s\n", CFStringToCString(name)); if (!userInfo) return; CFIndex count = CFDictionaryGetCount(userInfo); const void *keys[count]; const void *values[count]; CFDictionaryGetKeysAndValues(userInfo, keys, values); for(i = 0; i < count; i++) { printf("For i=%d, key: %s\n", i, CFStringToCString((CFStringRef)keys[i])); } } void apiNotificationCallback( CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { CFNumberRef number = (CFNumberRef) CFDictionaryGetValue(userInfo, CFSTR("SKYPE_API_CLIENT_ID")); int client_number = CFNumberToCInt(number); if (client_number != 999 && (!client_id || client_id != client_number)) { return; } CFStringRef string = (CFStringRef) CFDictionaryGetValue(userInfo, CFSTR("SKYPE_API_NOTIFICATION_STRING")); if (string && delegate && delegate->SkypeNotificationReceived) { delegate->SkypeNotificationReceived(string); } } void attachResponseCallback( CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { CFNumberRef responseNumber = (CFNumberRef)CFDictionaryGetValue(userInfo, CFSTR("SKYPE_API_ATTACH_RESPONSE")); int response = CFNumberToCInt(responseNumber); client_id = response; if (delegate && delegate->SkypeAttachResponse) { delegate->SkypeAttachResponse(response?1:0); } } void skypeQuitCallback( CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { if (delegate && delegate->SkypeBecameAvailable) delegate->SkypeBecameUnavailable(NULL); } void skypeAvailableCallback( CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { if (delegate && delegate->SkypeBecameAvailable) delegate->SkypeBecameAvailable(NULL); } // STANDARD SKYPE.H BITS: void RemoveSkypeDelegate(void); void SetSkypeDelegate(SkypeDelegate *aDelegate) { if (!aDelegate->clientApplicationName) { printf("Deletegate requires application name\n"); delegate = NULL; return; } if (delegate) { RemoveSkypeDelegate(); } delegate = aDelegate; CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); CFNotificationCenterAddObserver( center, delegate->clientApplicationName, apiNotificationCallback, CFSTR("SKSkypeAPINotification"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); CFNotificationCenterAddObserver( center, delegate->clientApplicationName, skypeQuitCallback, CFSTR("SKSkypeWillQuit"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); CFNotificationCenterAddObserver( center, delegate->clientApplicationName, skypeAvailableCallback, CFSTR("SKSkypeBecameAvailable"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); CFNotificationCenterAddObserver( center, delegate->clientApplicationName, availabilityUpdateCallback, CFSTR("SKAvailabilityUpdate"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); CFNotificationCenterAddObserver( center, delegate->clientApplicationName, attachResponseCallback, CFSTR("SKSkypeAttachResponse"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); } SkypeDelegate * GetSkypeDelegate(void) { return delegate; } void RemoveSkypeDelegate(void) { if (delegate && delegate->clientApplicationName) { CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); CFNotificationCenterRemoveObserver( center, delegate->clientApplicationName, CFSTR("SKSkypeAPINotification"), NULL); CFNotificationCenterRemoveObserver( center, delegate->clientApplicationName, CFSTR("SKSkypeWillQuit"), NULL); CFNotificationCenterRemoveObserver( center, delegate->clientApplicationName, CFSTR("SKSkypeBecameAvailable"), NULL); CFNotificationCenterRemoveObserver( center, delegate->clientApplicationName, CFSTR("SKAvailabilityUpdate"), NULL); CFNotificationCenterRemoveObserver( center, delegate->clientApplicationName, CFSTR("SKSkypeAttachResponse"), NULL); } delegate = NULL; } int IsSkypeAvailable(void) { //is skype available? isavailable = 0; CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); CFNotificationCenterPostNotification( center, CFSTR("SKSkypeAPIAvailabilityRequest"), NULL, NULL, TRUE); //Should only take 1 second or less to reply RunCurrentEventLoop(1); int avail = isavailable; isavailable = 0; return avail; } int IsSkypeRunning(void) { OSStatus status = noErr; ProcessSerialNumber psn = {kNoProcess, kNoProcess}; unsigned int procNameLength = 32; unsigned char procName[procNameLength]; unsigned int i = 0; ProcessInfoRec info; info.processInfoLength = sizeof(ProcessInfoRec); info.processName = procName; #if __LP64__ info.processAppRef = NULL; #else info.processAppSpec = NULL; #endif pid_t pid = 0; while(status == noErr) { for(i = 0; i < procNameLength; i++) procName[i] = '\0'; status = GetNextProcess(&psn); if (status == noErr) { if (GetProcessInformation(&psn, &info) == noErr) { //for some reason first character is poisioned if (g_str_equal((char *)&procName[1], "Skype")) { if (GetProcessPID(&psn, &pid) == noErr) { return (int)pid; } } } } } return 0; } void ConnectToSkype(void) { if (!delegate || !delegate->clientApplicationName) { printf("Error: Delegate not set\n"); return; } if (!IsSkypeAvailable()) { printf("Error: Skype not available\n"); } CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); //do the connect CFNotificationCenterPostNotification( center, CFSTR("SKSkypeAPIAttachRequest"), delegate->clientApplicationName, NULL, TRUE); } void SendSkypeCommand(CFStringRef command) { if (delegate == NULL) { printf("Can't send message, no delegate set\n"); return; } if (command == NULL) return; if (!client_id) { printf("Can't send message, not connected\n"); return; } CFRetain(command); CFNumberRef id_number = CFNumberCreate(NULL, kCFNumberIntType, &client_id); CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); const void *keys[] = {(void *)CFSTR("SKYPE_API_COMMAND"), (void *)CFSTR("SKYPE_API_CLIENT_ID")}; const void *values[] = {command, id_number}; CFDictionaryRef userInfo = CFDictionaryCreate(NULL, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); //send message CFNotificationCenterPostNotification( center, CFSTR("SKSkypeAPICommand"), NULL, userInfo, TRUE); CFRelease(command); CFRelease(id_number); CFRelease(userInfo); } void DisconnectFromSkype(void) { CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); if (client_id) { CFNumberRef id_number = CFNumberCreate(NULL, kCFNumberIntType, &client_id); const void *keys[] = {(void *)CFSTR("SKYPE_API_CLIENT_ID")}; const void *values[] = {id_number}; CFDictionaryRef userInfo = CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); //disconnect CFNotificationCenterPostNotification( center, CFSTR("SKSkypeAPIDetachRequest"), NULL, userInfo, TRUE); client_id = 0; } }