]> cgit.babelmonkeys.de Git - jubjub.git/blob - src/core/JubAvatarManager.m
Close subscription dialogs, when answered on another client
[jubjub.git] / src / core / JubAvatarManager.m
1 #import "JubAvatarManager.h"
2 #import "JubChatClient.h"
3
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"
8
9 @implementation JubAvatarManager
10 @synthesize delegate = _delegate;
11
12 - initWithClient: (JubChatClient*)client
13 {
14         self = [super init];
15
16         @try {
17                 _client = client;
18                 [_client.discoEntity
19                     addFeature: JUB_NS_AVATAR_METADATA @"+notify"];
20                 [_client.connection addDelegate: self];
21
22                 // Determine cache path
23                 OFDictionary *env = [OFApplication environment];
24                 OFString * xdgCache = env[@"XDG_CACHE_HOME"];
25
26                 cachePath = [OFMutableString new];
27                 if (xdgCache == nil) {
28                         OFString *home = env[@"HOME"];
29                         if (home == nil)
30                                 [cachePath appendString: @"/tmp"];
31                         else
32                                 [cachePath appendString: home];
33                         [cachePath appendString: @"/.cache"];
34                 } else
35                         [cachePath appendString: xdgCache];
36
37                 [cachePath appendString: @"/jubjub"];
38         } @catch (id e) {
39                 [self release];
40                 @throw e;
41         }
42
43         return self;
44 }
45
46 - (void)dealloc
47 {
48         // TODO: Remove feature
49         [cachePath release];
50         [_client.connection removeDelegate: self];
51         [super dealloc];
52 }
53
54 - (void)connection: (XMPPConnection*)connection
55  didReceiveMessage: (XMPPMessage*)message
56 {
57         OFXMLElement *event = [message elementForName: @"event"
58                                             namespace: JUB_NS_PUBSUB_EVENT];
59         if (event == nil)
60                 return;
61
62         OFXMLElement *items = [event elementForName: @"items"
63                                           namespace: JUB_NS_PUBSUB_EVENT];
64         if (items == nil ||
65             ![[[items attributeForName: @"node"] stringValue]
66               isEqual: JUB_NS_AVATAR_METADATA])
67                 return;
68
69         OFXMLElement *item = [items elementForName: @"item"
70                                          namespace: JUB_NS_PUBSUB_EVENT];
71         if (item == nil)
72                 return;
73
74         OFString *ID = [[item attributeForName: @"id"] stringValue];
75         if (ID == nil)
76                 return;
77
78         OFXMLElement *metadata = [item elementForName: @"metadata"
79                                             namespace: JUB_NS_AVATAR_METADATA];
80         if (metadata == nil)
81                 return;
82
83         OFXMLElement *info = [metadata elementForName: @"info"
84                                             namespace: JUB_NS_AVATAR_METADATA];
85         if (info == nil)
86                 return;
87
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
95                         return;
96                 [_delegate contact: contact
97                       didSetAvatar: avatarPath];
98                 return;
99         }
100
101         XMPPIQ *queryIQ =
102             [XMPPIQ IQWithType: @"get"
103                             ID: [_client.connection generateStanzaID]];
104         queryIQ.to = message.from;
105
106         OFXMLElement *pubsub = [OFXMLElement elementWithName: @"pubsub"
107                                                    namespace: JUB_NS_PUBSUB];
108         [queryIQ addChild: pubsub];
109
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];
116
117         OFXMLElement *queryItem =
118             [OFXMLElement elementWithName: @"item"
119                                 namespace: JUB_NS_PUBSUB];
120         [queryItem addAttributeWithName: @"id"
121                             stringValue: ID];
122         [queryItems addChild: queryItem];
123
124         [_client.connection sendIQ: queryIQ
125                     callbackTarget: self
126                           selector: @selector(Jub_connection:
127                                             receivedAvatarIQ:)];
128 }
129
130 - (void)Jub_connection: (XMPPConnection*)connection
131       receivedAvatarIQ: (XMPPIQ*)IQ
132 {
133         OFXMLElement *pubsub = [IQ elementForName: @"pubsub"
134                                         namespace: JUB_NS_PUBSUB];
135         if (pubsub == nil)
136                 return;
137
138         OFXMLElement *items = [pubsub elementForName: @"items"
139                                            namespace: JUB_NS_PUBSUB];
140         if (items == nil ||
141             ![[[items attributeForName: @"node"] stringValue]
142               isEqual: JUB_NS_AVATAR_DATA])
143                 return;
144
145         OFXMLElement *item = [items elementForName: @"item"
146                                          namespace: JUB_NS_PUBSUB];
147         if (item == nil)
148                 return;
149
150         OFString *ID = [[item attributeForName: @"id"] stringValue];
151         if (ID == nil)
152                 return;
153
154         OFXMLElement *data = [item elementForName: @"data"
155                                         namespace: JUB_NS_AVATAR_DATA];
156         if (data == nil)
157                 return;
158
159         OFDataArray *avatar =
160             [OFDataArray dataArrayWithBase64EncodedString: [data stringValue]];
161
162         if (![OFFile directoryExistsAtPath: cachePath])
163                 [OFFile createDirectoryAtPath: cachePath
164                                 createParents: true];
165
166         OFString *filename =
167             [cachePath stringByAppendingFormat: @"/%@.png", ID];
168         [avatar writeToFile: filename];
169
170         OFString *contactJID = [IQ.from bareJID];
171
172         XMPPContact *contact =
173             [_client.contactManager.contacts objectForKey: contactJID];
174         if (contact == nil) // Avatar for unknown contact
175                 return;
176
177         [_delegate contact: contact
178               didSetAvatar: filename];
179 }
180 @end