5 // Created by Matt Meissner on 10/30/09.
6 // Modified by Michael Lamb on 2/27/13
7 // Copyright 2013 Michael Lamb/Harris Kauffman. All rights reserved.
10 #import <AISharedAdium.h>
11 #import <Adium/AIStatus.h>
12 #import <Adium/AIStatusControllerProtocol.h>
14 #import "ESPurpleSIPEAccount.h"
15 #import "ESSIPEService.h"
17 #include "sipe-core.h"
18 #include "sipe-backend.h"
21 extern void AILog(NSString *fmt, ...);
23 @implementation ESPurpleSIPEAccount
25 - (const char*)protocolPlugin
30 - (NSString *)hostForPurple
32 NSString *server = [self preferenceForKey:KEY_SIPE_CONNECT_HOST group:GROUP_ACCOUNT_STATUS];
33 if (!server || [server length] == 0)
35 // set the KEY_CONNECT_HOST to "autodetect" just to make sure we don't lose it from the defaults
36 [self setPreference:@"autodetect" forKey:KEY_CONNECT_HOST group:GROUP_ACCOUNT_STATUS];
43 #pragma mark Account Configuration
44 - (void)configurePurpleAccount
46 [super configurePurpleAccount];
48 // Account preferences
49 AILog(@"Configuring account: %s\n", self.purpleAccountName);
51 // !!! ------ HACK/Kludge alert! ------
53 * Adium's CBPurpleAccount class's implementation of configurePurpleAccount (called above)
54 * has the following line:
56 * if (hostName && [hostName length]) {
58 * Which doesn't allow us to leave the KEY_CONNECT_HOST preference empty (Adium prompts for the user to fill it out)
59 * sipe-core is expecting the server account setting to be empty to engage the auto-detection piece. The only way
60 * to fix this is to fake out Adium by storing the servername in a different key (KEY_SIPE_CONNECT_HOST) and setting a
61 * default KEY_CONNECT_HOST to something. We then need to detect that we have an empty servername here, and
62 * "overwrite" the default placeholder with an empty string.
65 // if there is no host specified, we're looking to auto-detect
66 // TODO: change this to a checkbox, and enable/disable based on that. Leaving a field blank is bad UI design.
67 NSString *server = [self preferenceForKey:KEY_SIPE_CONNECT_HOST group:GROUP_ACCOUNT_STATUS];
69 // if the server is empty, clear it in purple account (because the defaults hack for the superclass set it to "autodetect"). Otherwise, use the one provided
70 if([server isEqualToString:@""])
72 purple_account_set_string(account,"server", "");
74 // NOP. Superclass already set this via the [self hostForPurple] response.
77 NSString *winLogin = [self preferenceForKey:KEY_SIPE_WINDOWS_LOGIN group:GROUP_ACCOUNT_STATUS];
78 NSString *completeUserName = [NSString stringWithUTF8String:[self purpleAccountName]];
80 if (winLogin && [winLogin length]) {
81 // Configure the complete username ("user@domain.com,DOMAIN\user")
82 completeUserName = [NSString stringWithFormat:@"%@,%@",completeUserName, winLogin];
83 purple_account_set_username(account, [completeUserName UTF8String]);
85 purple_account_set_username(account, self.purpleAccountName);
88 NSString *thePassword = [self preferenceForKey:KEY_SIPE_PASSWORD group:GROUP_ACCOUNT_STATUS];
89 if (thePassword && [thePassword length])
90 purple_account_set_password(account, [thePassword UTF8String]);
92 BOOL sso = [[self preferenceForKey:KEY_SIPE_SINGLE_SIGN_ON group:GROUP_ACCOUNT_STATUS] boolValue];
93 purple_account_set_bool(account, "sso", sso);
96 // Adium doesn't honor our "optional" password on account creation and will prompt if the password field is left blank, so we must force it to think there is one, but only if there isn't already a password saved
98 [self setPasswordTemporarily:@"placeholder"];
101 // Connection preferences
102 id connType = [self preferenceForKey:KEY_SIPE_CONNECTION_TYPE group:GROUP_ACCOUNT_STATUS];
103 if([connType isKindOfClass:[NSNumber class]])
105 // For backwards compatibility, we pick from an array if the preference is a NSNumber
106 NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:@"auto", @"tls", @"tcp", nil];
107 connType = (NSString *)[myArray objectAtIndex:[self preferenceForKey:KEY_SIPE_CONNECTION_TYPE group:GROUP_ACCOUNT_STATUS]];
109 purple_account_set_string(account, "transport", [connType UTF8String]);
111 NSString *authScheme = [self preferenceForKey:KEY_SIPE_AUTH_SCHEME group:GROUP_ACCOUNT_STATUS];
112 purple_account_set_string(account, "authentication", [authScheme UTF8String]);
114 NSString *userAgent = [self preferenceForKey:KEY_SIPE_USER_AGENT group:GROUP_ACCOUNT_STATUS];
115 purple_account_set_string(account, "useragent", (!userAgent.length) ? [userAgent UTF8String] : "" );
118 NSString *emailURL = [self preferenceForKey:KEY_SIPE_EMAIL_URL group:GROUP_ACCOUNT_STATUS];
119 purple_account_set_string(account, "email_usr", (!emailURL.length) ? [emailURL UTF8String] : "" );
121 // TODO: Use account name (user@domain) as default for this
122 NSString *email = [self preferenceForKey:KEY_SIPE_EMAIL group:GROUP_ACCOUNT_STATUS];
123 purple_account_set_string(account, "email", (!email.length) ? [email UTF8String] : "" );
125 // TODO: Use Windows Login (DOMAIN\user) as default for this
126 NSString *emailLogin = [self preferenceForKey:KEY_SIPE_EMAIL_LOGIN group:GROUP_ACCOUNT_STATUS];
127 purple_account_set_string(account, "email_login", (!emailLogin.length) ? [emailLogin UTF8String] : "" );
129 // TODO: Use default password as default for this
130 NSString *emailPassword = [self preferenceForKey:KEY_SIPE_EMAIL_PASSWORD group:GROUP_ACCOUNT_STATUS];
131 purple_account_set_string(account, "email_password", (!emailPassword.length) ? [emailPassword UTF8String] : "" );
133 // Group chat preferences
134 NSString *groupchatUser = [self preferenceForKey:KEY_SIPE_GROUP_CHAT_PROXY group:GROUP_ACCOUNT_STATUS];
135 purple_account_set_string(account, "groupchat_user", (!groupchatUser.length) ? [groupchatUser UTF8String] : "" );
140 #pragma mark File transfer
142 - (BOOL)canSendFolders
147 - (void)beginSendOfFileTransfer:(ESFileTransfer *)fileTransfer
149 [super _beginSendOfFileTransfer:fileTransfer];
152 - (void)acceptFileTransferRequest:(ESFileTransfer *)fileTransfer
154 [super acceptFileTransferRequest:fileTransfer];
157 - (void)rejectFileReceiveRequest:(ESFileTransfer *)fileTransfer
159 [super rejectFileReceiveRequest:fileTransfer];
162 - (void)cancelFileTransfer:(ESFileTransfer *)fileTransfer
164 [super cancelFileTransfer:fileTransfer];
167 #pragma mark Status Messages
169 * @brief Status name to use for a Purple buddy
171 - (NSString *)statusNameForPurpleBuddy:(PurpleBuddy *)buddy
173 NSString *statusName = [super statusNameForPurpleBuddy:buddy];
174 PurplePresence *presence = purple_buddy_get_presence(buddy);
175 PurpleStatus *status = purple_presence_get_active_status(presence);
176 const char *purpleStatusID = purple_status_get_id(status);
178 if (!purpleStatusID) return nil;
180 switch (sipe_status_token_to_activity(purpleStatusID))
182 case SIPE_ACTIVITY_AVAILABLE:
183 case SIPE_ACTIVITY_ONLINE:
184 statusName = STATUS_NAME_AVAILABLE;
186 case SIPE_ACTIVITY_AWAY:
187 case SIPE_ACTIVITY_INACTIVE:
188 statusName = STATUS_NAME_AWAY;
190 case SIPE_ACTIVITY_BRB:
191 statusName = STATUS_NAME_BRB;
193 case SIPE_ACTIVITY_BUSY:
194 case SIPE_ACTIVITY_BUSYIDLE:
195 statusName = STATUS_NAME_BUSY;
197 case SIPE_ACTIVITY_DND:
198 statusName = STATUS_NAME_DND;
200 case SIPE_ACTIVITY_LUNCH:
201 statusName = STATUS_NAME_LUNCH;
203 case SIPE_ACTIVITY_INVISIBLE:
204 statusName = STATUS_NAME_INVISIBLE;
206 case SIPE_ACTIVITY_OFFLINE:
207 statusName = STATUS_NAME_OFFLINE;
209 case SIPE_ACTIVITY_ON_PHONE:
210 statusName = STATUS_NAME_PHONE;
212 case SIPE_ACTIVITY_IN_CONF:
213 case SIPE_ACTIVITY_IN_MEETING:
214 statusName = STATUS_NAME_NOT_AT_DESK;
216 case SIPE_ACTIVITY_OOF:
217 statusName = STATUS_NAME_NOT_IN_OFFICE;
219 case SIPE_ACTIVITY_URGENT_ONLY:
220 statusName = STATUS_NAME_AWAY_FRIENDS_ONLY;
223 statusName = STATUS_NAME_OFFLINE;
231 * @brief Maps purple status IDs to Adium statuses
233 - (const char *)purpleStatusIDForStatus:(AIStatus *)statusState arguments:(NSMutableDictionary *)arguments
235 const gchar *statusID;
236 NSString *statusName = statusState.statusName;
237 NSString *statusMessageString = [statusState statusMessageString];
239 if (!statusMessageString) statusMessageString = @"";
241 // TODO: figure out why sipe_status_activity_to_token calls return junk, instead of a gchar*
242 switch (statusState.statusType) {
243 case AIAvailableStatusType:
244 statusID = sipe_activity_map[SIPE_ACTIVITY_AVAILABLE].status_id;
245 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_AVAILABLE);
248 case AIAwayStatusType:
249 if (([statusName isEqualToString:STATUS_NAME_AWAY]) ||
250 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_AWAY]] == NSOrderedSame))
252 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_AWAY);
253 statusID = sipe_activity_map[SIPE_ACTIVITY_AWAY].status_id;
254 } else if (([statusName isEqualToString:STATUS_NAME_BRB]) ||
255 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_BRB]] == NSOrderedSame))
257 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_BRB);
258 statusID = sipe_activity_map[SIPE_ACTIVITY_BRB].status_id;
259 } else if (([statusName isEqualToString:STATUS_NAME_BUSY]) ||
260 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_BUSY]] == NSOrderedSame))
262 // TODO: Figure out how to determine if they should be "busy" or "busyidle"
263 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_BUSY);
264 statusID = sipe_activity_map[SIPE_ACTIVITY_BUSY].status_id;
265 } else if (([statusName isEqualToString:STATUS_NAME_DND]) ||
266 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_DND]] == NSOrderedSame))
268 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_DND);
269 statusID = sipe_activity_map[SIPE_ACTIVITY_DND].status_id;
270 } else if (([statusName isEqualToString:STATUS_NAME_LUNCH]) ||
271 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_LUNCH]] == NSOrderedSame))
273 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_LUNCH);
274 statusID = sipe_activity_map[SIPE_ACTIVITY_LUNCH].status_id;
275 } else if (([statusName isEqualToString:STATUS_NAME_PHONE]) ||
276 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_PHONE]] == NSOrderedSame))
278 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_ON_PHONE);
279 statusID = sipe_activity_map[SIPE_ACTIVITY_ON_PHONE].status_id;
280 } else if (([statusName isEqualToString:STATUS_NAME_NOT_AT_DESK]) ||
281 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_NOT_AT_DESK]] == NSOrderedSame))
283 // TODO: Figure out how to determine if they should be "In a meeting" or "In a conference"
284 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING);
285 statusID = sipe_activity_map[SIPE_ACTIVITY_IN_MEETING].status_id;
286 } else if (([statusName isEqualToString:STATUS_NAME_NOT_IN_OFFICE]) ||
287 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_NOT_IN_OFFICE]] == NSOrderedSame))
289 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_OOF);
290 statusID = sipe_activity_map[SIPE_ACTIVITY_OOF].status_id;
291 } else if (([statusName isEqualToString:STATUS_NAME_AWAY_FRIENDS_ONLY]) ||
292 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_AWAY_FRIENDS_ONLY]] == NSOrderedSame))
294 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_URGENT_ONLY);
295 statusID = sipe_activity_map[SIPE_ACTIVITY_URGENT_ONLY].status_id;
298 case AIInvisibleStatusType:
299 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_INVISIBLE);
300 statusID = sipe_activity_map[SIPE_ACTIVITY_INVISIBLE].status_id;
303 case AIOfflineStatusType:
304 //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_OFFLINE);
305 statusID = sipe_activity_map[SIPE_ACTIVITY_OFFLINE].status_id;
310 //If we didn't get a purple status type, request one from super
311 if (statusID == NULL) statusID = [super purpleStatusIDForStatus:statusState arguments:arguments];