X-Git-Url: http://git.babelmonkeys.de/?a=blobdiff_plain;f=src%2Fcore%2FJubAvatarManager.m;fp=src%2Fcore%2FJubAvatarManager.m;h=7d2fe8fb97c6ebb83cd0004c2e3f6c015c5f1773;hb=fa3c174db5c04176d891b91f68491e6ac8e22c22;hp=0000000000000000000000000000000000000000;hpb=8752f8d229e67221a6178e0cc4cc888b6e8c292e;p=jubjub.git diff --git a/src/core/JubAvatarManager.m b/src/core/JubAvatarManager.m new file mode 100644 index 0000000..7d2fe8f --- /dev/null +++ b/src/core/JubAvatarManager.m @@ -0,0 +1,180 @@ +#import "JubAvatarManager.h" +#import "JubChatClient.h" + +#define JUB_NS_PUBSUB @"http://jabber.org/protocol/pubsub" +#define JUB_NS_PUBSUB_EVENT @"http://jabber.org/protocol/pubsub#event" +#define JUB_NS_AVATAR_DATA @"urn:xmpp:avatar:data" +#define JUB_NS_AVATAR_METADATA @"urn:xmpp:avatar:metadata" + +@implementation JubAvatarManager +@synthesize delegate = _delegate; + +- initWithClient: (JubChatClient*)client +{ + self = [super init]; + + @try { + _client = client; + [_client.discoEntity + addFeature: JUB_NS_AVATAR_METADATA @"+notify"]; + [_client.connection addDelegate: self]; + + // Determine cache path + OFDictionary *env = [OFApplication environment]; + OFString * xdgCache = env[@"XDG_CACHE_HOME"]; + + cachePath = [OFMutableString new]; + if (xdgCache == nil) { + OFString *home = env[@"HOME"]; + if (home == nil) + [cachePath appendString: @"/tmp"]; + else + [cachePath appendString: home]; + [cachePath appendString: @"/.cache"]; + } else + [cachePath appendString: xdgCache]; + + [cachePath appendString: @"/jubjub"]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + // TODO: Remove feature + [cachePath release]; + [_client.connection removeDelegate: self]; + [super dealloc]; +} + +- (void)connection: (XMPPConnection*)connection + didReceiveMessage: (XMPPMessage*)message +{ + OFXMLElement *event = [message elementForName: @"event" + namespace: JUB_NS_PUBSUB_EVENT]; + if (event == nil) + return; + + OFXMLElement *items = [event elementForName: @"items" + namespace: JUB_NS_PUBSUB_EVENT]; + if (items == nil || + ![[[items attributeForName: @"node"] stringValue] + isEqual: JUB_NS_AVATAR_METADATA]) + return; + + OFXMLElement *item = [items elementForName: @"item" + namespace: JUB_NS_PUBSUB_EVENT]; + if (item == nil) + return; + + OFString *ID = [[item attributeForName: @"id"] stringValue]; + if (ID == nil) + return; + + OFXMLElement *metadata = [item elementForName: @"metadata" + namespace: JUB_NS_AVATAR_METADATA]; + if (metadata == nil) + return; + + OFXMLElement *info = [metadata elementForName: @"info" + namespace: JUB_NS_AVATAR_METADATA]; + if (info == nil) + return; + + OFString *avatarPath = + [cachePath stringByAppendingFormat: @"/%@.png", ID]; + if ([OFFile fileExistsAtPath: avatarPath]) { + OFString *contactJID = [message.from bareJID]; + XMPPContact *contact = + [_client.contactManager.contacts objectForKey: contactJID]; + if (contact == nil) // Avatar for unknown contact + return; + [_delegate contact: contact + didSetAvatar: avatarPath]; + return; + } + + XMPPIQ *queryIQ = + [XMPPIQ IQWithType: @"get" + ID: [_client.connection generateStanzaID]]; + queryIQ.to = message.from; + + OFXMLElement *pubsub = [OFXMLElement elementWithName: @"pubsub" + namespace: JUB_NS_PUBSUB]; + [queryIQ addChild: pubsub]; + + OFXMLElement *queryItems = + [OFXMLElement elementWithName: @"items" + namespace: JUB_NS_PUBSUB]; + [queryItems addAttributeWithName: @"node" + stringValue: JUB_NS_AVATAR_DATA]; + [pubsub addChild: queryItems]; + + OFXMLElement *queryItem = + [OFXMLElement elementWithName: @"item" + namespace: JUB_NS_PUBSUB]; + [queryItem addAttributeWithName: @"id" + stringValue: ID]; + [queryItems addChild: queryItem]; + + [_client.connection sendIQ: queryIQ + callbackTarget: self + selector: @selector(Jub_connection: + receivedAvatarIQ:)]; +} + +- (void)Jub_connection: (XMPPConnection*)connection + receivedAvatarIQ: (XMPPIQ*)IQ +{ + OFXMLElement *pubsub = [IQ elementForName: @"pubsub" + namespace: JUB_NS_PUBSUB]; + if (pubsub == nil) + return; + + OFXMLElement *items = [pubsub elementForName: @"items" + namespace: JUB_NS_PUBSUB]; + if (items == nil || + ![[[items attributeForName: @"node"] stringValue] + isEqual: JUB_NS_AVATAR_DATA]) + return; + + OFXMLElement *item = [items elementForName: @"item" + namespace: JUB_NS_PUBSUB]; + if (item == nil) + return; + + OFString *ID = [[item attributeForName: @"id"] stringValue]; + if (ID == nil) + return; + + OFXMLElement *data = [item elementForName: @"data" + namespace: JUB_NS_AVATAR_DATA]; + if (data == nil) + return; + + OFDataArray *avatar = + [OFDataArray dataArrayWithBase64EncodedString: [data stringValue]]; + + if (![OFFile directoryExistsAtPath: cachePath]) + [OFFile createDirectoryAtPath: cachePath + createParents: true]; + + OFString *filename = + [cachePath stringByAppendingFormat: @"/%@.png", ID]; + [avatar writeToFile: filename]; + + OFString *contactJID = [IQ.from bareJID]; + + XMPPContact *contact = + [_client.contactManager.contacts objectForKey: contactJID]; + if (contact == nil) // Avatar for unknown contact + return; + + [_delegate contact: contact + didSetAvatar: filename]; +} +@end