1
+ //
2
+ // Created by Jonathon Staff on 10/11/14.
3
+ // Copyright (c) 2014 Jonathon Staff. All rights reserved.
4
+ //
5
+
6
+ #import " XMPPRegistration.h"
7
+ #import " XMPPStream.h"
8
+ #import " XMPPIDTracker.h"
9
+ #import " XMPPIQ.h"
10
+ #import " NSXMLElement+XMPP.h"
11
+
12
+ NSString *const XMPPRegistrationErrorDomain = @" XMPPRegistrationErrorDomain" ;
13
+
14
+ @implementation XMPPRegistration
15
+
16
+ - (void )didActivate
17
+ {
18
+ xmppIDTracker = [[XMPPIDTracker alloc ] initWithStream: xmppStream dispatchQueue: moduleQueue];
19
+ }
20
+
21
+ - (void )willDeactivate
22
+ {
23
+ [xmppIDTracker removeAllIDs ];
24
+ xmppIDTracker = nil ;
25
+ }
26
+
27
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
28
+ #pragma mark Public API
29
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
30
+
31
+ /* *
32
+ * This method provides functionality of XEP-0077 3.3 User Changes Password.
33
+ *
34
+ * @link {http://xmpp.org/extensions/xep-0077.html#usecases-changepw}
35
+ *
36
+ * Example 18. Password Change
37
+ *
38
+ * <iq type='set' to='shakespeare.lit' id='change1'>
39
+ * <query xmlns='jabber:iq:register'>
40
+ * <username>bill</username>
41
+ * <password>newpass</password>
42
+ * </query>
43
+ * </iq>
44
+ *
45
+ */
46
+ - (BOOL )changePassword : (NSString *)newPassword
47
+ {
48
+ if (![xmppStream isAuthenticated ])
49
+ return NO ; // You must be authenticated in order to change your password
50
+
51
+ dispatch_block_t block = ^{
52
+ @autoreleasepool {
53
+ NSString *toStr = xmppStream.myJID .domain ;
54
+ NSXMLElement *query = [NSXMLElement elementWithName: @" query" xmlns: @" jabber:iq:register" ];
55
+
56
+ NSXMLElement *username = [NSXMLElement elementWithName: @" username"
57
+ stringValue: xmppStream.myJID.user];
58
+ NSXMLElement *password = [NSXMLElement elementWithName: @" password"
59
+ stringValue: newPassword];
60
+ [query addChild: username];
61
+ [query addChild: password];
62
+
63
+ XMPPIQ *iq = [XMPPIQ iqWithType: @" set"
64
+ to: [XMPPJID jidWithString: toStr]
65
+ elementID: [xmppStream generateUUID ]
66
+ child: query];
67
+
68
+ [xmppIDTracker addID: [iq elementID ]
69
+ target: self
70
+ selector: @selector (handlePasswordChangeQueryIQ:withInfo: )
71
+ timeout: 60 ];
72
+
73
+ [xmppStream sendElement: iq];
74
+ }
75
+ };
76
+
77
+ if (dispatch_get_specific (moduleQueueTag))
78
+ block ();
79
+ else
80
+ dispatch_async (moduleQueue, block);
81
+
82
+ return YES ;
83
+ }
84
+
85
+ /* *
86
+ * This method provides functionality of XEP-0077 3.2 Entity Cancels an Existing Registration.
87
+ *
88
+ * @link {http://xmpp.org/extensions/xep-0077.html#usecases-cancel}
89
+ *
90
+ * <iq type='set' from='bill@shakespeare.lit/globe' id='unreg1'>
91
+ * <query xmlns='jabber:iq:register'>
92
+ * <remove/>
93
+ * </query>
94
+ * </iq>
95
+ *
96
+ */
97
+ - (BOOL )cancelRegistration
98
+ {
99
+ return [self cancelRegistrationUsingPassword: nil ];
100
+ }
101
+
102
+ /* *
103
+ * Same as cancelRegistration. Handling authentication challenges is not yet implemented.
104
+ */
105
+ - (BOOL )cancelRegistrationUsingPassword : (NSString *)password
106
+ {
107
+ // TODO: Handle the scenario of using password
108
+
109
+ dispatch_block_t block = ^{
110
+ @autoreleasepool {
111
+
112
+ NSXMLElement *remove = [NSXMLElement elementWithName: @" remove" ];
113
+ NSXMLElement *query = [NSXMLElement elementWithName: @" query" xmlns: @" jabber:iq:register" ];
114
+ [query addChild: remove ];
115
+ XMPPIQ *iq = [XMPPIQ iqWithType: @" set"
116
+ elementID: [xmppStream generateUUID ]
117
+ child: query];
118
+
119
+ [xmppIDTracker addElement: iq
120
+ target: self
121
+ selector: @selector (handleRegistrationCancelQueryIQ:withInfo: )
122
+ timeout: 60 ];
123
+
124
+ [xmppStream sendElement: iq];
125
+ }
126
+ };
127
+
128
+ if (dispatch_get_specific (moduleQueueTag))
129
+ block ();
130
+ else
131
+ dispatch_async (moduleQueue, block);
132
+
133
+ return YES ;
134
+ }
135
+
136
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
137
+ #pragma mark - XMPPIDTracker
138
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
139
+
140
+ /* *
141
+ * This method handles the response received (or not received) after calling changePassword.
142
+ */
143
+ - (void )handlePasswordChangeQueryIQ : (XMPPIQ *)iq withInfo : (XMPPBasicTrackingInfo *)info
144
+ {
145
+ dispatch_block_t block = ^{
146
+ @autoreleasepool {
147
+ NSXMLElement *errorElem = [iq elementForName: @" error" ];
148
+
149
+ if (errorElem) {
150
+ NSString *errMsg = [[errorElem children ] componentsJoinedByString: @" , " ];
151
+ NSInteger errCode = [errorElem attributeIntegerValueForName: @" code"
152
+ withDefaultValue: -1 ];
153
+ NSDictionary *errInfo = @{NSLocalizedDescriptionKey : errMsg};
154
+ NSError *err = [NSError errorWithDomain: XMPPRegistrationErrorDomain
155
+ code: errCode
156
+ userInfo: errInfo];
157
+
158
+ [multicastDelegate passwordChangeFailed: self
159
+ withError: err];
160
+ return ;
161
+ }
162
+
163
+ NSString *type = [iq type ];
164
+
165
+ if ([type isEqualToString: @" result" ] && iq.childCount == 0 ) {
166
+ [multicastDelegate passwordChangeSuccessful: self ];
167
+ } else {
168
+ // this should be impossible to reach, but just for safety's sake...
169
+ [multicastDelegate passwordChangeFailed: self
170
+ withError: nil ];
171
+ }
172
+ }
173
+ };
174
+
175
+ if (dispatch_get_specific (moduleQueueTag))
176
+ block ();
177
+ else
178
+ dispatch_async (moduleQueue, block);
179
+ }
180
+
181
+ /* *
182
+ * This method handles the response received (or not received) after calling cancelRegistration.
183
+ */
184
+ - (void )handleRegistrationCancelQueryIQ : (XMPPIQ *)iq withInfo : (XMPPBasicTrackingInfo *)info
185
+ {
186
+ dispatch_block_t block = ^{
187
+ @autoreleasepool {
188
+ NSXMLElement *errorElem = [iq elementForName: @" error" ];
189
+
190
+ if (errorElem) {
191
+ NSString *errMsg = [[errorElem children ] componentsJoinedByString: @" , " ];
192
+ NSInteger errCode = [errorElem attributeIntegerValueForName: @" code"
193
+ withDefaultValue: -1 ];
194
+ NSDictionary *errInfo = @{NSLocalizedDescriptionKey : errMsg};
195
+ NSError *err = [NSError errorWithDomain: XMPPRegistrationErrorDomain
196
+ code: errCode
197
+ userInfo: errInfo];
198
+
199
+ [multicastDelegate cancelRegistrationFailed: self
200
+ withError: err];
201
+ return ;
202
+ }
203
+
204
+ NSString *type = [iq type ];
205
+
206
+ if ([type isEqualToString: @" result" ] && iq.childCount == 0 ) {
207
+ [multicastDelegate cancelRegistrationSuccessful: self ];
208
+ } else {
209
+ // this should be impossible to reach, but just for safety's sake...
210
+ [multicastDelegate cancelRegistrationFailed: self
211
+ withError: nil ];
212
+ }
213
+ }
214
+ };
215
+
216
+ if (dispatch_get_specific (moduleQueueTag))
217
+ block ();
218
+ else
219
+ dispatch_async (moduleQueue, block);
220
+ }
221
+
222
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
223
+ #pragma mark - XMPPStreamDelegate
224
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
225
+
226
+ - (BOOL )xmppStream : (XMPPStream *)stream didReceiveIQ : (XMPPIQ *)iq
227
+ {
228
+ NSString *type = [iq type ];
229
+
230
+ if ([type isEqualToString: @" result" ] || [type isEqualToString: @" error" ]) {
231
+ NSLog (@" invoking with iq: %@ " , iq);
232
+ return [xmppIDTracker invokeForElement: iq withObject: iq];
233
+ }
234
+
235
+ return NO ;
236
+ }
237
+
238
+ @end
0 commit comments