Merge lp:~isoschiz/xmppframework/vcard-temp into lp:xmppframework

Proposed by Martin Morrison
Status: Needs review
Proposed branch: lp:~isoschiz/xmppframework/vcard-temp
Merge into: lp:xmppframework
Diff against target: 1663 lines (+1652/-0)
2 files modified
Extensions/XMPPvCardTemp.h (+294/-0)
Extensions/XMPPvCardTemp.m (+1358/-0)
To merge this branch: bzr merge lp:~isoschiz/xmppframework/vcard-temp
Reviewer Review Type Date Requested Status
XMPPFramework Developers Pending
Review via email: mp+33988@code.launchpad.net

Description of the change

Implementation of XEP-0054.

(Note: there are a few missing functions. Pushing this out for review of the API).

To post a comment you must log in.

Unmerged revisions

148. By Martin Morrison <email address hidden>

Implementation of XEP-0054. Note there are a few missing functions still, to be completed in a future commit.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'Extensions'
2=== added file 'Extensions/XMPPvCardTemp.h'
3--- Extensions/XMPPvCardTemp.h 1970-01-01 00:00:00 +0000
4+++ Extensions/XMPPvCardTemp.h 2010-08-28 10:45:53 +0000
5@@ -0,0 +1,294 @@
6+//
7+// XMPPvCardTemp.h
8+// Jibberer
9+//
10+// Created by Martin Morrison on 24/07/2010.
11+// Copyright 2010 __MyCompanyName__. All rights reserved.
12+//
13+
14+#import <Foundation/Foundation.h>
15+#import <CoreLocation/CoreLocation.h>
16+#if TARGET_OS_IPHONE
17+#import "DDXML.h"
18+#endif
19+
20+#import "XMPPJID.h"
21+#import "XMPPModule.h"
22+#import "XMPPStream.h"
23+#import "NSXMLElementAdditions.h"
24+
25+/*
26+ * Implementation of XEP-0054 vCard-temp
27+ *
28+ * Consists of the following classes/protocols:
29+ * - XMPPvCard - the XMPPModule. Instantiate one of these to fetch vCards.
30+ * - XMPPvCardStorage - protocol for persistence of vCards. A default in-memory implementation is provided.
31+ * - XMPPvCardDelegate - protocol for objects wishing to be notified of new vCards.
32+ *
33+ * The following are all NSXMLElement subclasses providing accessor methods for the supported fields:
34+ * - XMPPvCard - represents a <vCard/> element.
35+ * - XMPPvCardEmail - an <EMAIL/> child of a <vCard/> element.
36+ * - XMPPvCardTel - a <TEL/> child of a <vCard/> element.
37+ * - XMPPvCardAdr - an <ADR/> child of a <vCard/> element.
38+ * - XMPPvCardLabel - a <LABEL/> child of a <vCard/> element.
39+ * - (XMPPvCardAdrTypes - superclass of XMPPvCardAdr and XMPPvCardLabel providing common accessors).
40+ */
41+
42+#define XMPP_VCARD_NS @"vcard-temp"
43+
44+@protocol XMPPvCardTempDelegate;
45+@class XMPPvCard;
46+
47+#pragma mark -
48+#pragma mark XMPPvCardStorage
49+
50+@protocol XMPPvCardStorage <NSObject>
51+
52+/*
53+ * Return whether a vCard for the given JID is saved.
54+ */
55+- (BOOL)havevCardForJID:(XMPPJID *)jid;
56+
57+/*
58+ * Get the vCard for the given JID.
59+ */
60+- (XMPPvCard *)getvCardForJID:(XMPPJID *)jid;
61+
62+/*
63+ * Save the given vCard for the given JID.
64+ */
65+- (void)savevCard:(XMPPvCard *)vCard forJID:(XMPPJID *)jid;
66+
67+/*
68+ * Clear any stored vCard for the given JID.
69+ */
70+- (void)clearvCardForJID:(XMPPJID *)jid;
71+
72+@end
73+
74+/*
75+ * Basic storage implementation.
76+ */
77+@interface XMPPvCardMemoryStorage : NSObject <XMPPvCardStorage> {
78+ NSMutableDictionary *vcards;
79+}
80+@end
81+
82+#pragma mark -
83+#pragma mark XMPPvCardTemp
84+
85+/*
86+ * Provides a wrapper for XEP-0054
87+ */
88+@interface XMPPvCardTemp : XMPPModule <XMPPStreamDelegate> {
89+ XMPPvCard *myvCard;
90+ id <XMPPvCardStorage> storage;
91+ BOOL autoFetchvCards;
92+}
93+
94+@property (nonatomic, retain, readonly) id <XMPPvCardStorage> storage;
95+@property (nonatomic, assign) BOOL autoFetchvCards;
96+
97+/*
98+ * If storage is unspecified, uses a default memory backed cacher.
99+ */
100+- (id)initWithStream:(XMPPStream *)stream;
101+- (id)initWithStream:(XMPPStream *)stream storage:(id <XMPPvCardStorage>)storage;
102+
103+/*
104+ * Initiate a fetch for the vCard for the given user. If the storage object
105+ * already has a vCard for the given JID, then this has no effect.
106+ */
107+- (void)fetchvCardForJID:(XMPPJID *)jid;
108+
109+@end
110+
111+#pragma mark -
112+#pragma mark XMPPvCardAdrTypes
113+
114+@interface XMPPvCardAdrTypes : NSXMLElement
115+
116+@property (nonatomic, assign, setter=setHome) BOOL isHome;
117+@property (nonatomic, assign, setter=setWork) BOOL isWork;
118+@property (nonatomic, assign, setter=setParcel) BOOL isParcel;
119+@property (nonatomic, assign, setter=setPostal) BOOL isPostal;
120+@property (nonatomic, assign, setter=setDomestic) BOOL isDomestic;
121+@property (nonatomic, assign, setter=setInternational) BOOL isInternational;
122+@property (nonatomic, assign, setter=setPreferred) BOOL isPreferred;
123+
124+@end
125+
126+#pragma mark -
127+#pragma mark XMPPvCardAdr
128+
129+@interface XMPPvCardAdr : XMPPvCardAdrTypes
130+
131++ (XMPPvCardAdr *)vCardAdrFromElement:(NSXMLElement *)elem;
132+
133+@property (nonatomic, assign) NSString *pobox;
134+@property (nonatomic, assign) NSString *extendedAddress;
135+@property (nonatomic, assign) NSString *street;
136+@property (nonatomic, assign) NSString *locality;
137+@property (nonatomic, assign) NSString *region;
138+@property (nonatomic, assign) NSString *postalCode;
139+@property (nonatomic, assign) NSString *country;
140+
141+@end
142+
143+#pragma mark -
144+#pragma mark XMPPvCardLabel
145+
146+@interface XMPPvCardLabel : XMPPvCardAdrTypes
147+
148++ (XMPPvCardLabel *)vCardLabelFromElement:(NSXMLElement *)elem;
149+
150+@property (nonatomic, assign) NSArray *lines;
151+
152+@end
153+
154+#pragma mark -
155+#pragma mark XMPPvCardTel
156+
157+@interface XMPPvCardTel : NSXMLElement
158+
159++ (XMPPvCardTel *)vCardTelFromElement:(NSXMLElement *)elem;
160+
161+@property (nonatomic, assign, setter=setHome) BOOL isHome;
162+@property (nonatomic, assign, setter=setWork) BOOL isWork;
163+@property (nonatomic, assign, setter=setVoice) BOOL isVoice;
164+@property (nonatomic, assign, setter=setFax) BOOL isFax;
165+@property (nonatomic, assign, setter=setPager) BOOL isPager;
166+@property (nonatomic, assign, setter=setMessaging) BOOL hasMessaging;
167+@property (nonatomic, assign, setter=setCell) BOOL isCell;
168+@property (nonatomic, assign, setter=setVideo) BOOL isVideo;
169+@property (nonatomic, assign, setter=setBBS) BOOL isBBS;
170+@property (nonatomic, assign, setter=setModem) BOOL isModem;
171+@property (nonatomic, assign, setter=setISDN) BOOL isISDN;
172+@property (nonatomic, assign, setter=setPCS) BOOL isPCS;
173+@property (nonatomic, assign, setter=setPreferred) BOOL isPreferred;
174+@property (nonatomic, assign) NSString *number;
175+
176+@end
177+
178+#pragma mark -
179+#pragma mark XMPPvCardEmail
180+
181+@interface XMPPvCardEmail : NSXMLElement
182+
183++ (XMPPvCardEmail *)vCardEmailFromElement:(NSXMLElement *)elem;
184+
185+@property (nonatomic, assign, setter=setHome) BOOL isHome;
186+@property (nonatomic, assign, setter=setWork) BOOL isWork;
187+@property (nonatomic, assign, setter=setInternet) BOOL isInternet;
188+@property (nonatomic, assign, setter=setX400) BOOL isX400;
189+@property (nonatomic, assign, setter=setPreferred) BOOL isPreferred;
190+@property (nonatomic, assign) NSString *userid;
191+
192+@end
193+
194+#pragma mark -
195+#pragma mark XMPPvCard
196+
197+typedef enum _XMPPvCardClass {
198+ XMPPvCardClassNone,
199+ XMPPvCardClassPublic,
200+ XMPPvCardClassPrivate,
201+ XMPPvCardClassConfidential,
202+} XMPPvCardClass;
203+
204+/*
205+ * Note: according to the DTD, every fields bar N and FN can appear multiple times.
206+ * The provided accessors only support this for the field types where multiple
207+ * entries make sense - for the others, if required, the NSXMLElement accessors
208+ * must be used.
209+ */
210+@interface XMPPvCard : NSXMLElement
211+
212++ (XMPPvCard *)vCardFromElement:(NSXMLElement *)element;
213+
214+#pragma mark Identification Types
215+
216+@property (nonatomic, assign) NSDate *bday;
217+@property (nonatomic, assign) NSData *photo;
218+@property (nonatomic, assign) NSString *nickname;
219+@property (nonatomic, assign) NSString *formattedName;
220+@property (nonatomic, assign) NSString *familyName;
221+@property (nonatomic, assign) NSString *givenName;
222+@property (nonatomic, assign) NSString *middleName;
223+@property (nonatomic, assign) NSString *prefix;
224+@property (nonatomic, assign) NSString *suffix;
225+
226+#pragma mark Delivery Addressing Types
227+
228+@property (nonatomic, assign) NSArray *addresses;
229+- (void)addAddress:(XMPPvCardAdr *)adr;
230+- (void)removeAddress:(XMPPvCardAdr *)adr;
231+- (void)clearAddresses;
232+
233+@property (nonatomic, assign) NSArray *labels;
234+- (void)addLabel:(XMPPvCardLabel *)label;
235+- (void)removeLabel:(XMPPvCardLabel *)label;
236+- (void)clearLabels;
237+
238+@property (nonatomic, assign) NSArray *telecomsAddresses;
239+- (void)addTelecomsAddress:(XMPPvCardTel *)tel;
240+- (void)removeTelecomsAddress:(XMPPvCardTel *)tel;
241+- (void)clearTelecomsAddresses;
242+
243+@property (nonatomic, assign) NSArray *emailAddresses;
244+- (void)addEmailAddress:(XMPPvCardEmail *)email;
245+- (void)removeEmailAddress:(XMPPvCardEmail *)email;
246+- (void)clearEmailAddresses;
247+
248+@property (nonatomic, assign) XMPPJID *jid;
249+@property (nonatomic, assign) NSString *mailer;
250+
251+#pragma mark Geographical Types
252+
253+@property (nonatomic, assign) NSTimeZone *timeZone;
254+@property (nonatomic, assign) CLLocation *location;
255+
256+#pragma mark Organizational Types
257+
258+@property (nonatomic, assign) NSString *title;
259+@property (nonatomic, assign) NSString *role;
260+@property (nonatomic, assign) NSData *logo;
261+@property (nonatomic, assign) XMPPvCard *agent;
262+@property (nonatomic, assign) NSString *orgName;
263+
264+/*
265+ * ORGUNITs can only be set if there is already an ORGNAME. Otherwise, changes are ignored.
266+ */
267+@property (nonatomic, assign) NSArray *orgUnits;
268+
269+#pragma mark Explanatory Types
270+
271+@property (nonatomic, assign) NSArray *categories;
272+@property (nonatomic, assign) NSString *note;
273+@property (nonatomic, assign) NSString *prodid;
274+@property (nonatomic, assign) NSDate *revision;
275+@property (nonatomic, assign) NSString *sortString;
276+@property (nonatomic, assign) NSString *phoneticSound;
277+@property (nonatomic, assign) NSData *sound;
278+@property (nonatomic, assign) NSString *uid;
279+@property (nonatomic, assign) NSString *url;
280+@property (nonatomic, assign) NSString *version;
281+@property (nonatomic, assign) NSString *description;
282+
283+#pragma mark Security Types
284+
285+@property (nonatomic, assign) XMPPvCardClass privacyClass;
286+@property (nonatomic, assign) NSData *key;
287+@property (nonatomic, assign) NSString *keyType;
288+
289+@end
290+
291+#pragma mark -
292+#pragma mark XMPPvCardTempDelegate
293+
294+@protocol XMPPvCardTempDelegate
295+@optional
296+
297+- (void)xmppvCard:(XMPPvCardTemp *)vCardMod didReceivevCard:(XMPPvCard *)vCard forJID:(XMPPJID *)jid;
298+
299+@end
300\ No newline at end of file
301
302=== added file 'Extensions/XMPPvCardTemp.m'
303--- Extensions/XMPPvCardTemp.m 1970-01-01 00:00:00 +0000
304+++ Extensions/XMPPvCardTemp.m 2010-08-28 10:45:53 +0000
305@@ -0,0 +1,1358 @@
306+//
307+// XMPPvCardTemp.m
308+// Jibberer
309+//
310+// Created by Martin Morrison on 24/07/2010.
311+// Copyright 2010 __MyCompanyName__. All rights reserved.
312+//
313+
314+#import <objc/runtime.h>
315+
316+#import "XMPPvCardTemp.h"
317+#import "XMPPIQ.h"
318+#import "XMPPJID.h"
319+#import "XMPPPresence.h"
320+#import "XMPPStream.h"
321+#import "NSDataAdditions.h"
322+#import "XMPPDateTimeProfiles.h"
323+
324+#import "NSXMLElementAdditions.h"
325+
326+#define XMPP_VCARD_SET_EMPTY_CHILD(Set, Name) \
327+ if (Set) { \
328+ NSXMLElement *elem = [NSXMLElement elementWithName:(Name)]; \
329+ [self addChild:elem]; \
330+ } else if (!(Set)) { \
331+ [self removeChildAtIndex:[[self children] indexOfObject:[self elementForName:(Name)]]]; \
332+ }
333+
334+#define XMPP_VCARD_SET_STRING_CHILD(Value, Name) \
335+ NSXMLElement *elem = [self elementForName:(Name)]; \
336+ if ((Value) != nil) { \
337+ if (elem == nil) { \
338+ elem = [NSXMLElement elementWithName:(Name)]; \
339+ } \
340+ [elem setStringValue:(Value)]; \
341+ } else if (elem != nil) { \
342+ [self removeChildAtIndex:[[self children] indexOfObject:elem]]; \
343+ }
344+
345+#define XMPP_VCARD_SET_N_CHILD(Value, Name) \
346+ NSXMLElement *name = [self elementForName:@"N"]; \
347+ if ((Value) != nil && name == nil) { \
348+ name = [NSXMLElement elementWithName:@"N"]; \
349+ [self addChild:name]; \
350+ } \
351+ NSXMLElement *part = [name elementForName:(Name)]; \
352+ if ((Value) != nil && part == nil) { \
353+ part = [NSXMLElement elementWithName:(Name)]; \
354+ [name addChild:part]; \
355+ } \
356+ if (Value) { \
357+ [part setStringValue:(Value)]; \
358+ } else if (part != nil) { \
359+ /* N is mandatory, so we leave it in. */ \
360+ [name removeChildAtIndex:[[self children] indexOfObject:part]]; \
361+ }
362+
363+#pragma mark -
364+#pragma mark XMPPvCardMemoryStorage
365+
366+@implementation XMPPvCardMemoryStorage
367+
368+- (id)init {
369+ if (self == [super init]) {
370+ vcards = [[NSMutableDictionary alloc] init];
371+ }
372+
373+ return self;
374+}
375+
376+- (void)dealloc {
377+ [vcards release];
378+ [super dealloc];
379+}
380+
381+- (BOOL)havevCardForJID:(XMPPJID *)jid {
382+ return [vcards objectForKey:jid] != nil;
383+}
384+
385+- (XMPPvCard *)getvCardForJID:(XMPPJID *)jid {
386+ NSLog(@"+++++ Fetching vCard for %@: %@", jid, [[vcards objectForKey:jid] compactXMLString]);
387+ return [vcards objectForKey:jid];
388+}
389+
390+- (void)savevCard:(XMPPvCard *)vCard forJID:(XMPPJID *)jid {
391+ NSLog(@"+++++ Storing vCard for %@: %@", jid, [vCard compactXMLString]);
392+ [vcards setObject:vCard forKey:jid];
393+}
394+
395+- (void)clearvCardForJID:(XMPPJID *)jid {
396+ [vcards removeObjectForKey:jid];
397+}
398+
399+@end
400+
401+#pragma mark -
402+#pragma mark XMPPvCardTemp
403+
404+@implementation XMPPvCardTemp
405+
406+@synthesize autoFetchvCards;
407+@synthesize storage;
408+
409+- (id)initWithStream:(XMPPStream *)stream {
410+ return [self initWithStream:stream storage:[[[XMPPvCardMemoryStorage alloc] init] autorelease]];
411+}
412+
413+- (id)initWithStream:(XMPPStream *)stream storage:(id <XMPPvCardStorage>)aStorage {
414+ if (self == [super initWithStream:stream]) {
415+ storage = [aStorage retain];
416+ autoFetchvCards = NO;
417+ }
418+ return self;
419+}
420+
421+/*- (UIImage *)photoForJID:(XMPPJID *)jid {
422+ UIImage *image = nil;
423+
424+ NSXMLElement *vCard = [storage vCardForJID:jid];
425+ NSXMLElement *photo = [vCard elementForName:@"PHOTO"];
426+
427+ if (photo) {
428+ // There is a PHOTO element. It should have a TYPE and a BINVAL
429+ //NSXMLElement *fileType = [photo elementForName:@"TYPE"];
430+ NSXMLElement *binval = [photo elementForName:@"BINVAL"];
431+
432+ if (binval) {
433+ NSData *base64Data = [[binval stringValue] dataUsingEncoding:NSASCIIStringEncoding];
434+ NSData *decodedData = [base64Data base64Decoded];
435+
436+ image = [UIImage imageWithData:decodedData];
437+ }
438+ }
439+
440+ if (!image) {
441+ image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"user_48x48" ofType:@"png"]];
442+ }
443+
444+ return image;
445+}*/
446+
447+- (void)dealloc {
448+ [storage release];
449+ storage = nil;
450+
451+ [super dealloc];
452+}
453+
454+- (void)fetchvCardForJID:(XMPPJID *)jid {
455+ // Check whether we already have a vCard
456+ jid = [jid bareJID];
457+ if (![storage havevCardForJID:jid]) {
458+ // Not got it yet. Let's make a request for the vCard
459+ XMPPIQ *iq = [XMPPIQ iqWithType:@"get" to:jid];
460+ NSXMLElement *vCardElem = [NSXMLElement elementWithName:@"vCard" xmlns:XMPP_VCARD_NS];
461+
462+ [iq addChild:vCardElem];
463+
464+ [xmppStream sendElement:iq];
465+ }
466+}
467+
468+// Delegate protocol
469+
470+- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq {
471+ NSXMLElement *elem = [iq elementForName:@"vCard" xmlns:XMPP_VCARD_NS];
472+ NSLog(@"Received IQ in vCard module with elem: %@", elem);
473+ if (elem != nil) {
474+ XMPPvCard *vCard = [XMPPvCard vCardFromElement:elem];
475+ [storage savevCard:vCard forJID:[iq from]];
476+
477+ [multicastDelegate xmppvCard:self didReceivevCard:vCard forJID:[iq from]];
478+ }
479+
480+ return NO;
481+}
482+
483+- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
484+ // We use this to track online buddies
485+ if (autoFetchvCards &&
486+ [presence from] != [xmppStream myJID] &&
487+ [presence status] != @"unavailable" &&
488+ [presence from] != nil) {
489+
490+ [self fetchvCardForJID:[presence from]];
491+ }
492+}
493+
494+@end
495+
496+#pragma mark -
497+#pragma mark XMPPvCardAdrTypes
498+
499+@implementation XMPPvCardAdrTypes
500+
501+- (BOOL)isHome {
502+ return [self elementForName:@"HOME"] != nil;
503+}
504+
505+- (void)setHome:(BOOL)home {
506+ XMPP_VCARD_SET_EMPTY_CHILD(home && ![self isHome], @"HOME");
507+}
508+
509+- (BOOL)isWork {
510+ return [self elementForName:@"WORK"] != nil;
511+}
512+
513+- (void)setWork:(BOOL)work {
514+ XMPP_VCARD_SET_EMPTY_CHILD(work && ![self isWork], @"WORK");
515+}
516+
517+- (BOOL)isParcel {
518+ return [self elementForName:@"PARCEL"] != nil;
519+}
520+- (void)setParcel:(BOOL)parcel {
521+ XMPP_VCARD_SET_EMPTY_CHILD(parcel && ![self isParcel], @"PARCEL");
522+}
523+
524+- (BOOL)isPostal {
525+ return [self elementForName:@"POSTAL"] != nil;
526+}
527+- (void)setPostal:(BOOL)postal {
528+ XMPP_VCARD_SET_EMPTY_CHILD(postal && ![self isPostal], @"POSTAL");
529+}
530+
531+- (BOOL)isDomestic {
532+ return [self elementForName:@"DOM"] != nil;
533+}
534+- (void)setDomestic:(BOOL)dom {
535+ XMPP_VCARD_SET_EMPTY_CHILD(dom && ![self isDomestic], @"DOM");
536+ // INTL and DOM are mutually exclusive
537+ if (dom) {
538+ [self setInternational:NO];
539+ }
540+}
541+
542+- (BOOL)isInternational {
543+ return [self elementForName:@"INTL"] != nil;
544+}
545+- (void)setInternational:(BOOL)intl {
546+ XMPP_VCARD_SET_EMPTY_CHILD(intl && ![self isInternational], @"INTL");
547+ // INTL and DOM are mutually exclusive
548+ if (intl) {
549+ [self setDomestic:NO];
550+ }
551+}
552+
553+- (BOOL)isPreferred {
554+ return [self elementForName:@"PREF"] != nil;
555+}
556+- (void)setPreferred:(BOOL)pref {
557+ XMPP_VCARD_SET_EMPTY_CHILD(pref && ![self isPreferred], @"PREF");
558+}
559+
560+@end
561+
562+#pragma mark -
563+#pragma mark XMPPvCardAdr
564+
565+@implementation XMPPvCardAdr
566+
567++ (void)initialize {
568+ // We use the object_setClass method below to dynamically change the class from a standard NSXMLElement.
569+ // The size of the two classes is expected to be the same.
570+ //
571+ // If a developer adds instance methods to this class, bad things happen at runtime that are very hard to debug.
572+ // This check is here to aid future developers who may make this mistake.
573+ //
574+ // For Fearless And Experienced Objective-C Developers:
575+ // It may be possible to support adding instance variables to this class if you seriously need it.
576+ // To do so, try realloc'ing self after altering the class, and then initialize your variables.
577+
578+ size_t superSize = class_getInstanceSize([NSXMLElement class]);
579+ size_t ourSize = class_getInstanceSize([XMPPvCardAdr class]);
580+
581+ if (superSize != ourSize)
582+ {
583+ NSLog(@"Adding instance variables to XMPPvCardAdr is not currently supported!");
584+ exit(15);
585+ }
586+}
587+
588++ (XMPPvCardAdr *)vCardAdrFromElement:(NSXMLElement *)elem {
589+ object_setClass(elem, [XMPPvCardAdr class]);
590+
591+ return (XMPPvCardAdr *)elem;
592+}
593+
594+- (NSString *)pobox {
595+ return [[self elementForName:@"POBOX"] stringValue];
596+}
597+- (void)setPobox:(NSString *)pobox {
598+ XMPP_VCARD_SET_STRING_CHILD(pobox, @"POBOX");
599+}
600+
601+- (NSString *)extendedAddress {
602+ return [[self elementForName:@"EXTADD"] stringValue];
603+}
604+- (void)setExtendedAddress:(NSString *)extadd {
605+ XMPP_VCARD_SET_STRING_CHILD(extadd, @"EXTADD");
606+}
607+
608+- (NSString *)street {
609+ return [[self elementForName:@"STREET"] stringValue];
610+}
611+- (void)setStreet:(NSString *)street {
612+ XMPP_VCARD_SET_STRING_CHILD(street, @"STREET");
613+}
614+
615+- (NSString *)locality {
616+ return [[self elementForName:@"LOCALITY"] stringValue];
617+}
618+- (void)setLocality:(NSString *)locality {
619+ XMPP_VCARD_SET_STRING_CHILD(locality, @"LOCALITY");
620+}
621+
622+- (NSString *)region {
623+ return [[self elementForName:@"REGION"] stringValue];
624+}
625+- (void)setRegion:(NSString *)region {
626+ XMPP_VCARD_SET_STRING_CHILD(region, @"REGION");
627+}
628+
629+- (NSString *)postalCode {
630+ return [[self elementForName:@"PCODE"] stringValue];
631+}
632+- (void)setPostalCode:(NSString *)pcode {
633+ XMPP_VCARD_SET_STRING_CHILD(pcode, @"PCODE");
634+}
635+
636+- (NSString *)country {
637+ return [[self elementForName:@"CTRY"] stringValue];
638+}
639+- (void)setCountry:(NSString *)ctry {
640+ XMPP_VCARD_SET_STRING_CHILD(ctry, @"CTRY");
641+}
642+
643+@end
644+
645+#pragma mark -
646+#pragma mark XMPPvCardLabel
647+
648+@implementation XMPPvCardLabel
649+
650++ (void)initialize {
651+ // We use the object_setClass method below to dynamically change the class from a standard NSXMLElement.
652+ // The size of the two classes is expected to be the same.
653+ //
654+ // If a developer adds instance methods to this class, bad things happen at runtime that are very hard to debug.
655+ // This check is here to aid future developers who may make this mistake.
656+ //
657+ // For Fearless And Experienced Objective-C Developers:
658+ // It may be possible to support adding instance variables to this class if you seriously need it.
659+ // To do so, try realloc'ing self after altering the class, and then initialize your variables.
660+
661+ size_t superSize = class_getInstanceSize([NSXMLElement class]);
662+ size_t ourSize = class_getInstanceSize([XMPPvCardLabel class]);
663+
664+ if (superSize != ourSize)
665+ {
666+ NSLog(@"Adding instance variables to XMPPvCardLabel is not currently supported!");
667+ exit(15);
668+ }
669+}
670+
671++ (XMPPvCardLabel *)vCardLabelFromElement:(NSXMLElement *)elem {
672+ object_setClass(elem, [XMPPvCardLabel class]);
673+
674+ return (XMPPvCardLabel *)elem;
675+}
676+
677+- (NSArray *)lines {
678+ NSArray *elems = [self elementsForName:@"LINE"];
679+ NSMutableArray *lines = [[NSMutableArray alloc] initWithCapacity:[elems count]];
680+
681+ for (NSXMLElement *elem in elems) {
682+ [lines addObject:[elem stringValue]];
683+ }
684+
685+ NSArray *result = [NSArray arrayWithArray:lines];
686+ [lines release];
687+ return result;
688+}
689+- (void)setLines:(NSArray *)lines {
690+ NSArray *elems = [self elementsForName:@"LINE"];
691+
692+ for (NSXMLElement *elem in elems) {
693+ [self removeChildAtIndex:[[self children] indexOfObject:elem]];
694+ }
695+
696+ for (NSString *line in lines) {
697+ NSXMLElement *elem = [NSXMLElement elementWithName:@"LINE"];
698+ [elem setStringValue:line];
699+ [self addChild:elem];
700+ }
701+}
702+
703+@end
704+
705+#pragma mark -
706+#pragma mark XMPPvCardTel
707+
708+@implementation XMPPvCardTel
709+
710++ (void)initialize {
711+ // We use the object_setClass method below to dynamically change the class from a standard NSXMLElement.
712+ // The size of the two classes is expected to be the same.
713+ //
714+ // If a developer adds instance methods to this class, bad things happen at runtime that are very hard to debug.
715+ // This check is here to aid future developers who may make this mistake.
716+ //
717+ // For Fearless And Experienced Objective-C Developers:
718+ // It may be possible to support adding instance variables to this class if you seriously need it.
719+ // To do so, try realloc'ing self after altering the class, and then initialize your variables.
720+
721+ size_t superSize = class_getInstanceSize([NSXMLElement class]);
722+ size_t ourSize = class_getInstanceSize([XMPPvCardTel class]);
723+
724+ if (superSize != ourSize)
725+ {
726+ NSLog(@"Adding instance variables to XMPPvCardTel is not currently supported!");
727+ exit(15);
728+ }
729+}
730+
731++ (XMPPvCardTel *)vCardTelFromElement:(NSXMLElement *)elem {
732+ object_setClass(elem, [XMPPvCardTel class]);
733+
734+ return (XMPPvCardTel *)elem;
735+}
736+
737+- (BOOL)isHome {
738+ return [self elementForName:@"HOME"] != nil;
739+}
740+- (void)setHome:(BOOL)home {
741+ XMPP_VCARD_SET_EMPTY_CHILD(home && ![self isHome], @"HOME");
742+}
743+
744+- (BOOL)isWork {
745+ return [self elementForName:@"WORK"] != nil;
746+}
747+- (void)setWork:(BOOL)work {
748+ XMPP_VCARD_SET_EMPTY_CHILD(work && ![self isWork], @"WORK");
749+}
750+
751+- (BOOL)isVoice {
752+ return [self elementForName:@"VOICE"] != nil;
753+}
754+- (void)setVoice:(BOOL)voice {
755+ XMPP_VCARD_SET_EMPTY_CHILD(voice && ![self isVoice], @"VOICE");
756+}
757+
758+- (BOOL)isFax {
759+ return [self elementForName:@"FAX"] != nil;
760+}
761+- (void)setFax:(BOOL)fax {
762+ XMPP_VCARD_SET_EMPTY_CHILD(fax && ![self isFax], @"FAX");
763+}
764+
765+- (BOOL)isPager {
766+ return [self elementForName:@"PAGER"] != nil;
767+}
768+- (void)setPager:(BOOL)pager {
769+ XMPP_VCARD_SET_EMPTY_CHILD(pager && ![self isPager], @"PAGER");
770+}
771+
772+- (BOOL)hasMessaging {
773+ return [self elementForName:@"MSG"] != nil;
774+}
775+- (void)setMessaging:(BOOL)msg {
776+ XMPP_VCARD_SET_EMPTY_CHILD(msg && ![self hasMessaging], @"MSG");
777+}
778+
779+- (BOOL)isCell {
780+ return [self elementForName:@"CELL"] != nil;
781+}
782+- (void)setCell:(BOOL)cell {
783+ XMPP_VCARD_SET_EMPTY_CHILD(cell && ![self isCell], @"CELL");
784+}
785+
786+- (BOOL)isVideo {
787+ return [self elementForName:@"VIDEO"] != nil;
788+}
789+- (void)setVideo:(BOOL)video {
790+ XMPP_VCARD_SET_EMPTY_CHILD(video && ![self isVideo], @"VIDEO");
791+}
792+
793+- (BOOL)isBBS {
794+ return [self elementForName:@"BBS"] != nil;
795+}
796+- (void)setBBS:(BOOL)bbs {
797+ XMPP_VCARD_SET_EMPTY_CHILD(bbs && ![self isBBS], @"BBS");
798+}
799+
800+- (BOOL)isModem {
801+ return [self elementForName:@"MODEM"] != nil;
802+}
803+- (void)setModem:(BOOL)modem {
804+ XMPP_VCARD_SET_EMPTY_CHILD(modem && ![self isModem], @"MODEM");
805+}
806+
807+- (BOOL)isISDN {
808+ return [self elementForName:@"ISDN"] != nil;
809+}
810+- (void)setISDN:(BOOL)isdn {
811+ XMPP_VCARD_SET_EMPTY_CHILD(isdn && ![self isISDN], @"ISDN");
812+}
813+
814+- (BOOL)isPCS {
815+ return [self elementForName:@"PCS"] != nil;
816+}
817+- (void)setPCS:(BOOL)pcs {
818+ XMPP_VCARD_SET_EMPTY_CHILD(pcs && ![self isPCS], @"PCS");
819+}
820+
821+- (BOOL)isPreferred {
822+ return [self elementForName:@"PREF"] != nil;
823+}
824+- (void)setPreferred:(BOOL)pref {
825+ XMPP_VCARD_SET_EMPTY_CHILD(pref && ![self isPreferred], @"PREF");
826+}
827+
828+- (NSString *)number {
829+ return [[self elementForName:@"NUMBER"] stringValue];
830+}
831+- (void)setNumber:(NSString *)number {
832+ XMPP_VCARD_SET_STRING_CHILD(number, @"NUMBER");
833+}
834+
835+@end
836+
837+#pragma mark -
838+#pragma mark XMPPvCardEmail
839+
840+@implementation XMPPvCardEmail
841+
842++ (void)initialize {
843+ // We use the object_setClass method below to dynamically change the class from a standard NSXMLElement.
844+ // The size of the two classes is expected to be the same.
845+ //
846+ // If a developer adds instance methods to this class, bad things happen at runtime that are very hard to debug.
847+ // This check is here to aid future developers who may make this mistake.
848+ //
849+ // For Fearless And Experienced Objective-C Developers:
850+ // It may be possible to support adding instance variables to this class if you seriously need it.
851+ // To do so, try realloc'ing self after altering the class, and then initialize your variables.
852+
853+ size_t superSize = class_getInstanceSize([NSXMLElement class]);
854+ size_t ourSize = class_getInstanceSize([XMPPvCardEmail class]);
855+
856+ if (superSize != ourSize)
857+ {
858+ NSLog(@"Adding instance variables to XMPPvCardEmail is not currently supported!");
859+ exit(15);
860+ }
861+}
862+
863++ (XMPPvCardEmail *)vCardEmailFromElement:(NSXMLElement *)elem {
864+ object_setClass(elem, [XMPPvCardEmail class]);
865+
866+ return (XMPPvCardEmail *)elem;
867+}
868+
869+- (BOOL)isHome {
870+ return [self elementForName:@"HOME"] != nil;
871+}
872+- (void)setHome:(BOOL)home {
873+ XMPP_VCARD_SET_EMPTY_CHILD(home && ![self isHome], @"HOME");
874+}
875+
876+- (BOOL)isWork {
877+ return [self elementForName:@"WORK"] != nil;
878+}
879+- (void)setWork:(BOOL)work {
880+ XMPP_VCARD_SET_EMPTY_CHILD(work && ![self isWork], @"WORK");
881+}
882+
883+- (BOOL)isInternet {
884+ return [self elementForName:@"INTERNET"] != nil;
885+}
886+- (void)setInternet:(BOOL)internet {
887+ XMPP_VCARD_SET_EMPTY_CHILD(internet && ![self isInternet], @"INTERNET");
888+}
889+
890+- (BOOL)isX400 {
891+ return [self elementForName:@"X400"] != nil;
892+}
893+- (void)setX400:(BOOL)x400 {
894+ XMPP_VCARD_SET_EMPTY_CHILD(x400 && ![self isX400], @"X400");
895+}
896+
897+- (BOOL)isPreferred {
898+ return [self elementForName:@"PREF"] != nil;
899+}
900+- (void)setPreferred:(BOOL)pref {
901+ XMPP_VCARD_SET_EMPTY_CHILD(pref && ![self isPreferred], @"PREF");
902+}
903+
904+- (NSString *)userid {
905+ return [[self elementForName:@"USERID"] stringValue];
906+}
907+- (void)setUserid:(NSString *)userid {
908+ XMPP_VCARD_SET_STRING_CHILD(userid, @"USERID");
909+}
910+
911+@end
912+
913+#pragma mark -
914+#pragma mark XMPPvCard
915+
916+@implementation XMPPvCard
917+
918++ (void)initialize {
919+ // We use the object_setClass method below to dynamically change the class from a standard NSXMLElement.
920+ // The size of the two classes is expected to be the same.
921+ //
922+ // If a developer adds instance methods to this class, bad things happen at runtime that are very hard to debug.
923+ // This check is here to aid future developers who may make this mistake.
924+ //
925+ // For Fearless And Experienced Objective-C Developers:
926+ // It may be possible to support adding instance variables to this class if you seriously need it.
927+ // To do so, try realloc'ing self after altering the class, and then initialize your variables.
928+
929+ size_t superSize = class_getInstanceSize([NSXMLElement class]);
930+ size_t ourSize = class_getInstanceSize([XMPPvCard class]);
931+
932+ if (superSize != ourSize)
933+ {
934+ NSLog(@"Adding instance variables to XMPPvCard is not currently supported!");
935+ exit(15);
936+ }
937+}
938+
939++ (XMPPvCard *)vCardFromElement:(NSXMLElement *)elem {
940+ object_setClass(elem, [XMPPvCard class]);
941+
942+ return (XMPPvCard *)elem;
943+}
944+
945+#pragma mark Identification Types
946+
947+- (NSDate *)bday {
948+ NSDate *bday = nil;
949+ NSXMLElement *elem = [self elementForName:@"BDAY"];
950+
951+ if (elem != nil) {
952+ bday = [NSDate dateWithXmppDateString:[elem stringValue]];
953+ }
954+
955+ return bday;
956+}
957+- (void)setBday:(NSDate *)bday {
958+ NSXMLElement *elem = [self elementForName:@"BDAY"];
959+
960+ if (elem == nil) {
961+ elem = [NSXMLElement elementWithName:@"BDAY"];
962+ [self addChild:elem];
963+ }
964+
965+ [elem setStringValue:[bday xmppDateString]];
966+}
967+
968+- (NSData *)photo {
969+ NSData *decodedData = nil;
970+ NSXMLElement *photo = [self elementForName:@"PHOTO"];
971+
972+ if (photo != nil) {
973+ // There is a PHOTO element. It should have a TYPE and a BINVAL
974+ //NSXMLElement *fileType = [photo elementForName:@"TYPE"];
975+ NSXMLElement *binval = [photo elementForName:@"BINVAL"];
976+
977+ if (binval) {
978+ NSData *base64Data = [[binval stringValue] dataUsingEncoding:NSASCIIStringEncoding];
979+ decodedData = [base64Data base64Decoded];
980+ }
981+ }
982+
983+ return decodedData;
984+}
985+- (void)setPhoto:(NSData *)data {
986+ NSXMLElement *photo = [self elementForName:@"PHOTO"];
987+
988+ if (photo == nil) {
989+ photo = [NSXMLElement elementWithName:@"PHOTO"];
990+ [self addChild:photo];
991+ }
992+
993+ NSXMLElement *binval = [photo elementForName:@"BINVAL"];
994+
995+ if (binval == nil) {
996+ binval = [NSXMLElement elementWithName:@"BINVAL"];
997+ [photo addChild:binval];
998+ }
999+
1000+ [binval setStringValue:[data base64Encoded]];
1001+}
1002+
1003+- (NSString *)nickname {
1004+ return [[self elementForName:@"NICKNAME"] stringValue];
1005+}
1006+- (void)setNickname:(NSString *)nick {
1007+ XMPP_VCARD_SET_STRING_CHILD(nick, @"NICKNAME");
1008+}
1009+
1010+- (NSString *)formattedName {
1011+ return [[self elementForName:@"FN"] stringValue];
1012+}
1013+- (void)setFormattedName:(NSString *)fn {
1014+ XMPP_VCARD_SET_STRING_CHILD(fn, @"FN");
1015+}
1016+
1017+- (NSString *)familyName {
1018+ NSString *result = nil;
1019+ NSXMLElement *name = [self elementForName:@"N"];
1020+
1021+ if (name != nil) {
1022+ NSXMLElement *part = [name elementForName:@"FAMILY"];
1023+
1024+ if (part != nil) {
1025+ result = [part stringValue];
1026+ }
1027+ }
1028+
1029+ return result;
1030+}
1031+- (void)setFamilyName:(NSString *)family {
1032+ XMPP_VCARD_SET_N_CHILD(family, @"FAMILY");
1033+}
1034+
1035+- (NSString *)givenName {
1036+ NSString *result = nil;
1037+ NSXMLElement *name = [self elementForName:@"N"];
1038+
1039+ if (name != nil) {
1040+ NSXMLElement *part = [name elementForName:@"GIVEN"];
1041+
1042+ if (part != nil) {
1043+ result = [part stringValue];
1044+ }
1045+ }
1046+
1047+ return result;
1048+}
1049+- (void)setGivenName:(NSString *)given {
1050+ XMPP_VCARD_SET_N_CHILD(given, @"GIVEN");
1051+}
1052+
1053+- (NSString *)middleName {
1054+ NSString *result = nil;
1055+ NSXMLElement *name = [self elementForName:@"N"];
1056+
1057+ if (name != nil) {
1058+ NSXMLElement *part = [name elementForName:@"MIDDLE"];
1059+
1060+ if (part != nil) {
1061+ result = [part stringValue];
1062+ }
1063+ }
1064+
1065+ return result;
1066+}
1067+- (void)setMiddleName:(NSString *)middle {
1068+ XMPP_VCARD_SET_N_CHILD(middle, @"MIDDLE");
1069+}
1070+
1071+- (NSString *)prefix {
1072+ NSString *result = nil;
1073+ NSXMLElement *name = [self elementForName:@"N"];
1074+
1075+ if (name != nil) {
1076+ NSXMLElement *part = [name elementForName:@"PREFIX"];
1077+
1078+ if (part != nil) {
1079+ result = [part stringValue];
1080+ }
1081+ }
1082+
1083+ return result;
1084+}
1085+- (void)setPrefix:(NSString *)prefix {
1086+ XMPP_VCARD_SET_N_CHILD(prefix, @"PREFIX");
1087+}
1088+
1089+- (NSString *)suffix {
1090+ NSString *result = nil;
1091+ NSXMLElement *name = [self elementForName:@"N"];
1092+
1093+ if (name != nil) {
1094+ NSXMLElement *part = [name elementForName:@"SUFFIC"];
1095+
1096+ if (part != nil) {
1097+ result = [part stringValue];
1098+ }
1099+ }
1100+
1101+ return result;
1102+}
1103+- (void)setSuffix:(NSString *)suffix {
1104+ XMPP_VCARD_SET_N_CHILD(suffix, @"SUFFIX");
1105+}
1106+
1107+#pragma mark Delivery Addressing Types
1108+
1109+- (NSArray *)addresses { return nil; }
1110+- (void)addAddress:(XMPPvCardAdr *)adr { }
1111+- (void)removeAddress:(XMPPvCardAdr *)adr { }
1112+- (void)setAddresses:(NSArray *)adrs { }
1113+- (void)clearAddresses { }
1114+
1115+- (NSArray *)labels { return nil; }
1116+- (void)addLabel:(XMPPvCardLabel *)label { }
1117+- (void)removeLabel:(XMPPvCardLabel *)label { }
1118+- (void)setLabels:(NSArray *)labels { }
1119+- (void)clearLabels { }
1120+
1121+- (NSArray *)telecomsAddresses { return nil; }
1122+- (void)addTelecomsAddress:(XMPPvCardTel *)tel { }
1123+- (void)removeTelecomsAddress:(XMPPvCardTel *)tel { }
1124+- (void)setTelecomsAddresses:(NSArray *)tels { }
1125+- (void)clearTelecomsAddresses { }
1126+
1127+- (NSArray *)emailAddresses { return nil; }
1128+- (void)addEmailAddress:(XMPPvCardEmail *)email { }
1129+- (void)removeEmailAddress:(XMPPvCardEmail *)email { }
1130+- (void)setEmailAddresses:(NSArray *)emails { }
1131+- (void)clearEmailAddresses { }
1132+
1133+- (XMPPJID *)jid {
1134+ XMPPJID *jid = nil;
1135+ NSXMLElement *elem = [self elementForName:@"JABBERID"];
1136+
1137+ if (elem != nil) {
1138+ jid = [XMPPJID jidWithString:[elem stringValue]];
1139+ }
1140+
1141+ return jid;
1142+}
1143+- (void)setJid:(XMPPJID *)jid {
1144+ NSXMLElement *elem = [self elementForName:@"JABBERID"];
1145+
1146+ if (elem == nil && jid != nil) {
1147+ elem = [NSXMLElement elementWithName:@"JABBERID"];
1148+ [self addChild:elem];
1149+ }
1150+
1151+ if (jid != nil) {
1152+ [elem setStringValue:[jid full]];
1153+ } else if (elem != nil) {
1154+ [self removeChildAtIndex:[[self children] indexOfObject:elem]];
1155+ }
1156+}
1157+
1158+- (NSString *)mailer {
1159+ return [[self elementForName:@"MAILER"] stringValue];
1160+}
1161+- (void)setMailer:(NSString *)mailer {
1162+ XMPP_VCARD_SET_STRING_CHILD(mailer, @"MAILER");
1163+}
1164+
1165+#pragma mark Geographical Types
1166+
1167+- (NSTimeZone *)timeZone {
1168+ // Turns out this is hard. Being lazy for now (not like anyone actually uses this, right?)
1169+ NSXMLElement *tz = [self elementForName:@"TZ"];
1170+ if (tz != nil) {
1171+ // This is unlikely to work. :-(
1172+ return [NSTimeZone timeZoneWithName:[tz stringValue]];
1173+ } else {
1174+ return nil;
1175+ }
1176+}
1177+- (void)setTimeZone:(NSTimeZone *)tz {
1178+ NSXMLElement *elem = [self elementForName:@"TZ"];
1179+
1180+ if (elem == nil && tz != nil) {
1181+ elem = [NSXMLElement elementWithName:@"TZ"];
1182+ [self addChild:elem];
1183+ }
1184+
1185+ if (tz != nil) {
1186+ NSInteger offset = [tz secondsFromGMT];
1187+ [elem setStringValue:[NSString stringWithFormat:@"%02d:%02d", offset / 3600, (offset % 3600) / 60]];
1188+ } else if (elem != nil) {
1189+ [self removeChildAtIndex:[[self children] indexOfObject:elem]];
1190+ }
1191+}
1192+
1193+- (CLLocation *)location {
1194+ CLLocation *loc = nil;
1195+ NSXMLElement *geo = [self elementForName:@"GEO"];
1196+
1197+ if (geo != nil) {
1198+ NSXMLElement *lat = [geo elementForName:@"LAT"];
1199+ NSXMLElement *lon = [geo elementForName:@"LON"];
1200+
1201+ loc = [[[CLLocation alloc] initWithLatitude:[[lat stringValue] doubleValue] longitude:[[lon stringValue] doubleValue]] autorelease];
1202+ }
1203+
1204+ return loc;
1205+}
1206+- (void)setLocation:(CLLocation *)geo {
1207+ NSXMLElement *elem = [self elementForName:@"GEO"];
1208+ NSXMLElement *lat;
1209+ NSXMLElement *lon;
1210+
1211+ if (geo != nil) {
1212+ CLLocationCoordinate2D coord = [geo coordinate];
1213+ if (elem == nil) {
1214+ elem = [NSXMLElement elementWithName:@"GEO"];
1215+ [self addChild:elem];
1216+
1217+ lat = [NSXMLElement elementWithName:@"LAT"];
1218+ [elem addChild:lat];
1219+ lon = [NSXMLElement elementWithName:@"LON"];
1220+ [elem addChild:lon];
1221+ } else {
1222+ lat = [elem elementForName:@"LAT"];
1223+ lon = [elem elementForName:@"LON"];
1224+ }
1225+
1226+ [lat setStringValue:[NSString stringWithFormat:@"%.6f", coord.latitude]];
1227+ [lon setStringValue:[NSString stringWithFormat:@"%.6f", coord.longitude]];
1228+ } else if (elem != nil) {
1229+ [self removeChildAtIndex:[[self children] indexOfObject:elem]];
1230+ }
1231+}
1232+
1233+#pragma mark Organizational Types
1234+
1235+- (NSString *)title {
1236+ return [[self elementForName:@"TITLE"] stringValue];
1237+}
1238+- (void)setTitle:(NSString *)title {
1239+ XMPP_VCARD_SET_STRING_CHILD(title, @"TITLE");
1240+}
1241+
1242+- (NSString *)role {
1243+ return [[self elementForName:@"ROLE"] stringValue];
1244+}
1245+- (void)setRole:(NSString *)role {
1246+ XMPP_VCARD_SET_STRING_CHILD(role, @"ROLE");
1247+}
1248+
1249+- (NSData *)logo {
1250+ NSData *decodedData = nil;
1251+ NSXMLElement *logo = [self elementForName:@"LOGO"];
1252+
1253+ if (logo != nil) {
1254+ // There is a LOGO element. It should have a TYPE and a BINVAL
1255+ //NSXMLElement *fileType = [photo elementForName:@"TYPE"];
1256+ NSXMLElement *binval = [logo elementForName:@"BINVAL"];
1257+
1258+ if (binval) {
1259+ NSData *base64Data = [[binval stringValue] dataUsingEncoding:NSASCIIStringEncoding];
1260+ decodedData = [base64Data base64Decoded];
1261+ }
1262+ }
1263+
1264+ return decodedData;
1265+}
1266+- (void)setLogo:(NSData *)data {
1267+ NSXMLElement *logo = [self elementForName:@"LOGO"];
1268+
1269+ if (logo == nil) {
1270+ logo = [NSXMLElement elementWithName:@"LOGO"];
1271+ [self addChild:logo];
1272+ }
1273+
1274+ NSXMLElement *binval = [logo elementForName:@"BINVAL"];
1275+
1276+ if (binval == nil) {
1277+ binval = [NSXMLElement elementWithName:@"BINVAL"];
1278+ [logo addChild:binval];
1279+ }
1280+
1281+ [binval setStringValue:[data base64Encoded]];
1282+}
1283+
1284+- (XMPPvCard *)agent {
1285+ XMPPvCard *agent = nil;
1286+ NSXMLElement *elem = [self elementForName:@"AGENT"];
1287+
1288+ if (elem != nil) {
1289+ agent = [XMPPvCard vCardFromElement:elem];
1290+ }
1291+
1292+ return agent;
1293+}
1294+- (void)setAgent:(XMPPvCard *)agent {
1295+ NSXMLElement *elem = [self elementForName:@"AGENT"];
1296+
1297+ if (elem != nil) {
1298+ [self removeChildAtIndex:[[self children] indexOfObject:elem]];
1299+ }
1300+
1301+ if (agent != nil) {
1302+ [self addChild:agent];
1303+ }
1304+}
1305+
1306+- (NSString *)orgName {
1307+ NSString *result = nil;
1308+ NSXMLElement *org = [self elementForName:@"ORG"];
1309+
1310+ if (org != nil) {
1311+ NSXMLElement *orgname = [org elementForName:@"ORGNAME"];
1312+
1313+ if (orgname != nil) {
1314+ result = [orgname stringValue];
1315+ }
1316+ }
1317+
1318+ return result;
1319+}
1320+- (void)setOrgName:(NSString *)orgname {
1321+ NSXMLElement *org = [self elementForName:@"ORG"];
1322+ NSXMLElement *elem = nil;
1323+
1324+ if (orgname != nil) {
1325+ if (org == nil) {
1326+ org = [NSXMLElement elementWithName:@"ORG"];
1327+ [self addChild:org];
1328+ } else {
1329+ elem = [org elementForName:@"ORGNAME"];
1330+ }
1331+
1332+ if (elem == nil) {
1333+ elem = [NSXMLElement elementWithName:@"ORGNAME"];
1334+ [org addChild:elem];
1335+ }
1336+
1337+ [elem setStringValue:orgname];
1338+ } else if (org != nil) {
1339+ // This implicitly removes all orgunits too, as per the spec
1340+ [self removeChildAtIndex:[[self children] indexOfObject:org]];
1341+ }
1342+}
1343+
1344+- (NSArray *)orgUnits {
1345+ NSArray *result = nil;
1346+ NSXMLElement *org = [self elementForName:@"ORG"];
1347+
1348+ if (org != nil) {
1349+ NSArray *elems = [org elementsForName:@"ORGUNIT"];
1350+ NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:[elems count]];
1351+
1352+ for (NSXMLElement *elem in elems) {
1353+ [arr addObject:[elem stringValue]];
1354+ }
1355+
1356+ result = [NSArray arrayWithArray:arr];
1357+ [arr release];
1358+ }
1359+
1360+ return result;
1361+}
1362+- (void)setOrgUnits:(NSArray *)orgunits {
1363+ NSXMLElement *org = [self elementForName:@"ORG"];
1364+
1365+ // If there is no org, then there is nothing to do (need ORGNAME first)
1366+ if (org != nil) {
1367+ NSArray *elems = [org elementsForName:@"ORGUNIT"];
1368+ for (NSXMLElement *elem in elems) {
1369+ [org removeChildAtIndex:[[org children] indexOfObject:elem]];
1370+ }
1371+
1372+ for (NSString *unit in orgunits) {
1373+ NSXMLElement *elem = [NSXMLElement elementWithName:@"ORGUNIT"];
1374+ [elem setStringValue:unit];
1375+
1376+ [org addChild:elem];
1377+ }
1378+ }
1379+}
1380+
1381+#pragma mark Explanatory Types
1382+
1383+- (NSArray *)categories {
1384+ NSArray *result = nil;
1385+ NSXMLElement *categories = [self elementForName:@"CATEGORIES"];
1386+
1387+ if (categories != nil) {
1388+ NSArray *elems = [categories elementsForName:@"KEYWORD"];
1389+ NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:[elems count]];
1390+
1391+ for (NSXMLElement *elem in elems) {
1392+ [arr addObject:[elem stringValue]];
1393+ }
1394+
1395+ result = [NSArray arrayWithArray:arr];
1396+ [arr release];
1397+ }
1398+
1399+ return result;
1400+}
1401+- (void)setCategories:(NSArray *)categories {
1402+ NSXMLElement *cat = [self elementForName:@"CATEGORIES"];
1403+
1404+ if (categories != nil) {
1405+ if (cat == nil) {
1406+ cat = [NSXMLElement elementWithName:@"CATEGORIES"];
1407+ [self addChild:cat];
1408+ }
1409+
1410+ NSArray *elems = [cat elementsForName:@"KEYWORD"];
1411+ for (NSXMLElement *elem in elems) {
1412+ [cat removeChildAtIndex:[[cat children] indexOfObject:elem]];
1413+ }
1414+
1415+ for (NSString *kw in categories) {
1416+ NSXMLElement *elem = [NSXMLElement elementWithName:@"KEYWORD"];
1417+ [elem setStringValue:kw];
1418+
1419+ [cat addChild:elem];
1420+ }
1421+ } else if (cat != nil) {
1422+ [self removeChildAtIndex:[[self children] indexOfObject:cat]];
1423+ }
1424+}
1425+
1426+- (NSString *)note {
1427+ return [[self elementForName:@"NOTE"] stringValue];
1428+}
1429+- (void)setNote:(NSString *)note {
1430+ XMPP_VCARD_SET_STRING_CHILD(note, @"NOTE");
1431+}
1432+
1433+- (NSString *)prodid {
1434+ return [[self elementForName:@"PRODID"] stringValue];
1435+}
1436+- (void)setProdid:(NSString *)prodid {
1437+ XMPP_VCARD_SET_STRING_CHILD(prodid, @"PRODID");
1438+}
1439+
1440+- (NSDate *)revision {
1441+ NSDate *rev = nil;
1442+ NSXMLElement *elem = [self elementForName:@"REV"];
1443+
1444+ if (elem != nil) {
1445+ rev = [NSDate dateWithXmppDateTimeString:[elem stringValue]];
1446+ }
1447+
1448+ return rev;
1449+}
1450+- (void)setRevision:(NSDate *)rev {
1451+ NSXMLElement *elem = [self elementForName:@"REV"];
1452+
1453+ if (elem == nil) {
1454+ elem = [NSXMLElement elementWithName:@"REV"];
1455+ [self addChild:elem];
1456+ }
1457+
1458+ [elem setStringValue:[rev xmppDateTimeString]];
1459+}
1460+
1461+- (NSString *)sortString {
1462+ return [[self elementForName:@"SORT-STRING"] stringValue];
1463+}
1464+- (void)setSortString:(NSString *)sortString {
1465+ XMPP_VCARD_SET_STRING_CHILD(sortString, @"SORT-STRING");
1466+}
1467+
1468+- (NSString *)phoneticSound {
1469+ NSString *phon = nil;
1470+ NSXMLElement *sound = [self elementForName:@"SOUND"];
1471+
1472+ if (sound != nil) {
1473+ NSXMLElement *elem = [sound elementForName:@"PHONETIC"];
1474+
1475+ if (elem != nil) {
1476+ phon = [elem stringValue];
1477+ }
1478+ }
1479+
1480+ return phon;
1481+}
1482+- (void)setPhoneticSound:(NSString *)phonetic {
1483+ NSXMLElement *sound = [self elementForName:@"SOUND"];
1484+ NSXMLElement *elem;
1485+
1486+ if (sound == nil && phonetic != nil) {
1487+ sound = [NSXMLElement elementWithName:@"SOUND"];
1488+ [self addChild:sound];
1489+ }
1490+
1491+ if (sound != nil) {
1492+ elem = [sound elementForName:@"PHONETIC"];
1493+
1494+ if (elem != nil && phonetic != nil) {
1495+ elem = [NSXMLElement elementWithName:@"PHONETIC"];
1496+ [sound addChild:elem];
1497+ }
1498+ }
1499+
1500+ if (phonetic != nil) {
1501+ [elem setStringValue:phonetic];
1502+ } else if (sound != nil) {
1503+ [self removeChildAtIndex:[[self children] indexOfObject:phonetic]];
1504+ }
1505+}
1506+
1507+- (NSData *)sound {
1508+ NSData *decodedData = nil;
1509+ NSXMLElement *sound = [self elementForName:@"SOUND"];
1510+
1511+ if (sound != nil) {
1512+ NSXMLElement *binval = [sound elementForName:@"BINVAL"];
1513+
1514+ if (binval) {
1515+ NSData *base64Data = [[binval stringValue] dataUsingEncoding:NSASCIIStringEncoding];
1516+ decodedData = [base64Data base64Decoded];
1517+ }
1518+ }
1519+
1520+ return decodedData;
1521+}
1522+- (void)setSound:(NSData *)data {
1523+ NSXMLElement *sound = [self elementForName:@"SOUND"];
1524+
1525+ if (sound == nil) {
1526+ sound = [NSXMLElement elementWithName:@"SOUND"];
1527+ [self addChild:sound];
1528+ }
1529+
1530+ NSXMLElement *binval = [sound elementForName:@"BINVAL"];
1531+
1532+ if (binval == nil) {
1533+ binval = [NSXMLElement elementWithName:@"BINVAL"];
1534+ [sound addChild:binval];
1535+ }
1536+
1537+ [binval setStringValue:[data base64Encoded]];
1538+}
1539+
1540+- (NSString *)uid {
1541+ return [[self elementForName:@"UID"] stringValue];
1542+}
1543+- (void)setUid:(NSString *)uid {
1544+ XMPP_VCARD_SET_STRING_CHILD(uid, @"UID");
1545+}
1546+
1547+- (NSString *)url {
1548+ return [[self elementForName:@"URL"] stringValue];
1549+}
1550+- (void)setUrl:(NSString *)url {
1551+ XMPP_VCARD_SET_STRING_CHILD(url, @"URL");
1552+}
1553+
1554+- (NSString *)version {
1555+ return [self attributeStringValueForName:@"version"];
1556+}
1557+- (void)setVersion:(NSString *)version {
1558+ [self addAttributeWithName:@"version" stringValue:version];
1559+}
1560+
1561+- (NSString *)description {
1562+ return [[self elementForName:@"DESC"] stringValue];
1563+}
1564+- (void)setDescription:(NSString *)desc {
1565+ XMPP_VCARD_SET_STRING_CHILD(desc, @"DESC");
1566+}
1567+
1568+#pragma mark Security Types
1569+
1570+- (XMPPvCardClass)privacyClass {
1571+ XMPPvCardClass priv = XMPPvCardClassNone;
1572+ NSXMLElement *elem = [self elementForName:@"CLASS"];
1573+
1574+ if (elem != nil) {
1575+ if ([elem elementForName:@"PUBLIC"] != nil) {
1576+ priv = XMPPvCardClassPublic;
1577+ } else if ([elem elementForName:@"PRIVATE"] != nil) {
1578+ priv = XMPPvCardClassPrivate;
1579+ } else if ([elem elementForName:@"CONFIDENTIAL"] != nil) {
1580+ priv = XMPPvCardClassConfidential;
1581+ }
1582+ }
1583+
1584+ return priv;
1585+}
1586+- (void)setPrivacyClass:(XMPPvCardClass)privacyClass {
1587+ NSXMLElement *elem = [self elementForName:@"CLASS"];
1588+
1589+ if (elem == nil && privacyClass != XMPPvCardClassNone) {
1590+ elem = [NSXMLElement elementWithName:@"CLASS"];
1591+ }
1592+
1593+ if (elem != nil) {
1594+ for (NSString *cls in [NSArray arrayWithObjects:@"PUBLIC", @"PRIVATE", @"CONFIDENTIAL", nil]) {
1595+ NSXMLElement *priv = [elem elementForName:cls];
1596+ if (priv != nil) {
1597+ [elem removeChildAtIndex:[[elem children] indexOfObject:priv]];
1598+ }
1599+ }
1600+
1601+ switch (privacyClass) {
1602+ case XMPPvCardClassPublic:
1603+ [elem addChild:[NSXMLElement elementWithName:@"PUBLIC"]];
1604+ break;
1605+ case XMPPvCardClassPrivate:
1606+ [elem addChild:[NSXMLElement elementWithName:@"PRIVATE"]];
1607+ break;
1608+ case XMPPvCardClassConfidential:
1609+ [elem addChild:[NSXMLElement elementWithName:@"CONFIDENTIAL"]];
1610+ break;
1611+ default:
1612+ case XMPPvCardClassNone:
1613+ // Remove the whole element
1614+ [self removeChildAtIndex:[[self children] indexOfObject:elem]];
1615+ break;
1616+ }
1617+ }
1618+}
1619+
1620+- (NSData *)key { return nil; }
1621+- (void)setKey:(NSData *)key { }
1622+
1623+- (NSString *)keyType {
1624+ NSString *typ = nil;
1625+ NSXMLElement *key = [self elementForName:@"KEY"];
1626+
1627+ if (key != nil) {
1628+ NSXMLElement *elem = [key elementForName:@"TYPE"];
1629+
1630+ if (elem != nil) {
1631+ typ = [elem stringValue];
1632+ }
1633+ }
1634+
1635+ return typ;
1636+}
1637+- (void)setKeyType:(NSString *)type {
1638+ NSXMLElement *key = [self elementForName:@"KEY"];
1639+ NSXMLElement *elem;
1640+
1641+ if (key == nil && type != nil) {
1642+ key = [NSXMLElement elementWithName:@"KEY"];
1643+ [self addChild:key];
1644+ }
1645+
1646+ if (key != nil) {
1647+ elem = [key elementForName:@"TYPE"];
1648+
1649+ if (elem != nil && type != nil) {
1650+ elem = [NSXMLElement elementWithName:@"TYPE"];
1651+ [key addChild:elem];
1652+ }
1653+ }
1654+
1655+ if (type != nil) {
1656+ [elem setStringValue:type];
1657+ } else if (key != nil) {
1658+ [self removeChildAtIndex:[[self children] indexOfObject:key]];
1659+ }
1660+}
1661+
1662+@end
1663+

Subscribers

People subscribed via source and target branches

to all changes: