1 #import "JubAvatarManager.h"
2 #import "JubChatClient.h"
4 #define JUB_NS_PUBSUB @"http://jabber.org/protocol/pubsub"
5 #define JUB_NS_PUBSUB_EVENT @"http://jabber.org/protocol/pubsub#event"
6 #define JUB_NS_AVATAR_DATA @"urn:xmpp:avatar:data"
7 #define JUB_NS_AVATAR_METADATA @"urn:xmpp:avatar:metadata"
9 @implementation JubAvatarManager
10 @synthesize delegate = _delegate;
12 - initWithClient: (JubChatClient*)client
19 addFeature: JUB_NS_AVATAR_METADATA @"+notify"];
20 [_client.connection addDelegate: self];
22 // Determine cache path
23 OFDictionary *env = [OFApplication environment];
24 OFString * xdgCache = env[@"XDG_CACHE_HOME"];
26 cachePath = [OFMutableString new];
27 if (xdgCache == nil) {
28 OFString *home = env[@"HOME"];
30 [cachePath appendString: @"/tmp"];
32 [cachePath appendString: home];
33 [cachePath appendString: @"/.cache"];
35 [cachePath appendString: xdgCache];
37 [cachePath appendString: @"/jubjub"];
48 // TODO: Remove feature
50 [_client.connection removeDelegate: self];
54 - (void)connection: (XMPPConnection*)connection
55 didReceiveMessage: (XMPPMessage*)message
57 OFXMLElement *event = [message elementForName: @"event"
58 namespace: JUB_NS_PUBSUB_EVENT];
62 OFXMLElement *items = [event elementForName: @"items"
63 namespace: JUB_NS_PUBSUB_EVENT];
65 ![[[items attributeForName: @"node"] stringValue]
66 isEqual: JUB_NS_AVATAR_METADATA])
69 OFXMLElement *item = [items elementForName: @"item"
70 namespace: JUB_NS_PUBSUB_EVENT];
74 OFString *ID = [[item attributeForName: @"id"] stringValue];
78 OFXMLElement *metadata = [item elementForName: @"metadata"
79 namespace: JUB_NS_AVATAR_METADATA];
83 OFXMLElement *info = [metadata elementForName: @"info"
84 namespace: JUB_NS_AVATAR_METADATA];
88 OFString *avatarPath =
89 [cachePath stringByAppendingFormat: @"/%@.png", ID];
90 if ([OFFile fileExistsAtPath: avatarPath]) {
91 OFString *contactJID = [message.from bareJID];
92 XMPPContact *contact =
93 [_client.contactManager.contacts objectForKey: contactJID];
94 if (contact == nil) // Avatar for unknown contact
96 [_delegate contact: contact
97 didSetAvatar: avatarPath];
102 [XMPPIQ IQWithType: @"get"
103 ID: [_client.connection generateStanzaID]];
104 queryIQ.to = message.from;
106 OFXMLElement *pubsub = [OFXMLElement elementWithName: @"pubsub"
107 namespace: JUB_NS_PUBSUB];
108 [queryIQ addChild: pubsub];
110 OFXMLElement *queryItems =
111 [OFXMLElement elementWithName: @"items"
112 namespace: JUB_NS_PUBSUB];
113 [queryItems addAttributeWithName: @"node"
114 stringValue: JUB_NS_AVATAR_DATA];
115 [pubsub addChild: queryItems];
117 OFXMLElement *queryItem =
118 [OFXMLElement elementWithName: @"item"
119 namespace: JUB_NS_PUBSUB];
120 [queryItem addAttributeWithName: @"id"
122 [queryItems addChild: queryItem];
124 [_client.connection sendIQ: queryIQ
126 selector: @selector(Jub_connection:
130 - (void)Jub_connection: (XMPPConnection*)connection
131 receivedAvatarIQ: (XMPPIQ*)IQ
133 OFXMLElement *pubsub = [IQ elementForName: @"pubsub"
134 namespace: JUB_NS_PUBSUB];
138 OFXMLElement *items = [pubsub elementForName: @"items"
139 namespace: JUB_NS_PUBSUB];
141 ![[[items attributeForName: @"node"] stringValue]
142 isEqual: JUB_NS_AVATAR_DATA])
145 OFXMLElement *item = [items elementForName: @"item"
146 namespace: JUB_NS_PUBSUB];
150 OFString *ID = [[item attributeForName: @"id"] stringValue];
154 OFXMLElement *data = [item elementForName: @"data"
155 namespace: JUB_NS_AVATAR_DATA];
159 OFDataArray *avatar =
160 [OFDataArray dataArrayWithBase64EncodedString: [data stringValue]];
162 if (![OFFile directoryExistsAtPath: cachePath])
163 [OFFile createDirectoryAtPath: cachePath
164 createParents: true];
167 [cachePath stringByAppendingFormat: @"/%@.png", ID];
168 [avatar writeToFile: filename];
170 OFString *contactJID = [IQ.from bareJID];
172 XMPPContact *contact =
173 [_client.contactManager.contacts objectForKey: contactJID];
174 if (contact == nil) // Avatar for unknown contact
177 [_delegate contact: contact
178 didSetAvatar: filename];