adium: General fixes in preparation for release
[siplcs.git] / src / adium / ESPurpleSIPEAccount.m
blob923ab8b1bf7bd26fdfd122360d9e7b09bbc6fb09
1 //
2 //  ESSIPEAccount.m
3 //  SIPEAdiumPlugin
4 //
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.
8 //
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"
20 // C Declarations
21 extern void AILog(NSString *fmt, ...);
23 @implementation ESPurpleSIPEAccount
25 - (const char*)protocolPlugin
27         return "prpl-sipe";
30 - (NSString *)hostForPurple
32     NSString *server = [self preferenceForKey:KEY_SIPE_CONNECT_HOST group:GROUP_ACCOUNT_STATUS];
33     if (!server || [server length] == 0)
34     {
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];
37         return @"autodetect";
38     } else {
39         return server;
40     }
43 #pragma mark Account Configuration
44 - (void)configurePurpleAccount
46         [super configurePurpleAccount];
47     
48     // Account preferences
49     AILog(@"Configuring account: %s\n", self.purpleAccountName);
50     
51     // !!! ------  HACK/Kludge alert!  ------
52     /*
53      * Adium's CBPurpleAccount class's implementation of configurePurpleAccount (called above)
54      * has the following line:
55      *
56      *         if (hostName && [hostName length]) {
57      * 
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.
63      */
64     
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];
68     
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:@""])
71     {
72         purple_account_set_string(account,"server", "");
73     } else {
74         // NOP.  Superclass already set this via the [self hostForPurple] response.
75     }
76         
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]);
84     } else {
85         purple_account_set_username(account, self.purpleAccountName);
86     }
87     
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);
94     
95     if (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
97             if (!thePassword)
98                 [self setPasswordTemporarily:@"placeholder"];
99     }
100     
101     // Connection preferences
102     id connType = [self preferenceForKey:KEY_SIPE_CONNECTION_TYPE group:GROUP_ACCOUNT_STATUS];
103     if([connType isKindOfClass:[NSNumber class]])
104         {
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]];
108         } 
109     purple_account_set_string(account, "transport", [connType UTF8String]);
110     
111     NSString *authScheme = [self preferenceForKey:KEY_SIPE_AUTH_SCHEME group:GROUP_ACCOUNT_STATUS];
112     purple_account_set_string(account, "authentication", [authScheme UTF8String]);
113     
114         NSString *userAgent = [self preferenceForKey:KEY_SIPE_USER_AGENT group:GROUP_ACCOUNT_STATUS];
115     purple_account_set_string(account, "useragent", (!userAgent.length) ?  [userAgent UTF8String] : "" );
116     
117     // Email preferences
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] : "" );
124     
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] : "" );
132     
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] : "" );
136     
140 #pragma mark File transfer
142 - (BOOL)canSendFolders
144         return NO;
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
170  */
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);
177     
178     if (!purpleStatusID) return nil;
179     
180     switch (sipe_status_token_to_activity(purpleStatusID))
181     {
182         case SIPE_ACTIVITY_AVAILABLE:
183         case SIPE_ACTIVITY_ONLINE:
184             statusName = STATUS_NAME_AVAILABLE;
185             break;
186         case SIPE_ACTIVITY_AWAY:
187         case SIPE_ACTIVITY_INACTIVE:
188             statusName = STATUS_NAME_AWAY;
189             break;
190         case SIPE_ACTIVITY_BRB:
191             statusName = STATUS_NAME_BRB;
192             break;
193         case SIPE_ACTIVITY_BUSY:
194         case SIPE_ACTIVITY_BUSYIDLE:
195             statusName = STATUS_NAME_BUSY;
196             break;
197         case SIPE_ACTIVITY_DND:
198             statusName = STATUS_NAME_DND;
199             break;
200         case SIPE_ACTIVITY_LUNCH:
201             statusName = STATUS_NAME_LUNCH;
202             break;
203         case SIPE_ACTIVITY_INVISIBLE:
204             statusName = STATUS_NAME_INVISIBLE;
205             break;
206         case SIPE_ACTIVITY_OFFLINE:
207             statusName = STATUS_NAME_OFFLINE;
208             break;
209         case SIPE_ACTIVITY_ON_PHONE:
210             statusName = STATUS_NAME_PHONE;
211             break;
212         case SIPE_ACTIVITY_IN_CONF:
213         case SIPE_ACTIVITY_IN_MEETING:
214             statusName = STATUS_NAME_NOT_AT_DESK;
215             break;
216         case SIPE_ACTIVITY_OOF:
217             statusName = STATUS_NAME_NOT_IN_OFFICE;
218             break;
219         case SIPE_ACTIVITY_URGENT_ONLY:
220             statusName = STATUS_NAME_AWAY_FRIENDS_ONLY;
221             break;
222         default:
223             statusName = STATUS_NAME_OFFLINE;
224     }
225    
226     return statusName; 
227     
231  * @brief Maps purple status IDs to Adium statuses
232  */
233  - (const char *)purpleStatusIDForStatus:(AIStatus *)statusState arguments:(NSMutableDictionary *)arguments
235      const gchar    *statusID;
236      NSString           *statusName = statusState.statusName;
237      NSString           *statusMessageString = [statusState statusMessageString];
238      
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);
246              break;
247              
248          case AIAwayStatusType:
249              if (([statusName isEqualToString:STATUS_NAME_AWAY]) ||
250                  ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_AWAY]] == NSOrderedSame))
251              {
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))
256              {
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))
261              {
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))
267              {
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))
272              {
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))
277              {
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))
282              {
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))
288              {
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))
293              {
294                  //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_URGENT_ONLY);
295                  statusID = sipe_activity_map[SIPE_ACTIVITY_URGENT_ONLY].status_id;
296              }
297          
298          case AIInvisibleStatusType:
299              //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_INVISIBLE);
300              statusID = sipe_activity_map[SIPE_ACTIVITY_INVISIBLE].status_id;
301              break;
302          
303          case AIOfflineStatusType:
304              //statusID = sipe_status_activity_to_token(SIPE_ACTIVITY_OFFLINE);
305              statusID = sipe_activity_map[SIPE_ACTIVITY_OFFLINE].status_id;
306              break;
307      }
308      
309          
310      //If we didn't get a purple status type, request one from super
311      if (statusID == NULL) statusID = [super purpleStatusIDForStatus:statusState arguments:arguments];
312      
313      return statusID;
317 @end