--- /dev/null
+CPPFLAGS += -Wall -g
+LIBS += -lobjxmpp
+
+.SILENT:
+
+all:
+ objfw-compile $(CPPFLAGS) $(LIBS) -o mpdbot src/*.m
+
+clean:
+ rm src/*.o
+++ /dev/null
-@interface PEPThread: OFThread
-- (void)MPD_connect;
-- (OFMutableDictionary*)MPD_responseFromSocket: (OFTCPSocket*)sock;
-
-OFTCPSocket *sock;
-@end
+++ /dev/null
-#import <ObjFW/ObjFW.h>
-#import <ObjXMPP/ObjXMPP.h>
-
-#import "PEPThread.h"
-
-#define NS_PUBSUB @"http://jabber.org/protocol/pubsub"
-#define NS_TUNE @"http://jabber.org/protocol/tune"
-
-@implementation PEPThread: OFThread
-- (void)dealloc
-{
- [sock release];
-
- [super dealloc];
-}
-
-- (void)MPD_connect
-{
- int64_t pause = 1;
- while(1) {
- @try {
- [sock release];
- sock = [[OFTCPSocket alloc] init];
- [sock connectToHost: @"localhost"
- port: 6600];
- return;
- } @catch (id e) {
- of_log(@"Connection failed, retrying in %" PRIi64
- " seconds", pause);
- [OFThread sleepForTimeInterval: pause];
- if (pause < 120)
- pause *= 2;
- [e release];
- }
- }
-}
-
-- (OFMutableDictionary*)MPD_responseFromSocket: (OFTCPSocket*)sock
-{
- OFString *answer;
- OFMutableDictionary *response = [OFMutableDictionary dictionary];
- while ((answer = [sock readLine]) && ![answer hasPrefix: @"OK"]) {
- size_t index;
- index = [answer indexOfFirstOccurrenceOfString: @":"];
- if (index == OF_INVALID_INDEX)
- continue;
- [response setObject: [answer substringFromIndex: index + 2
- toIndex: answer.length]
- forKey: [answer substringFromIndex: 0
- toIndex: index]];
- }
-
- return response;
-}
-
-- (id)main
-{
- [self MPD_connect];
- [self MPD_responseFromSocket: sock];
- while (1) {
- OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
- @try {
- OFMutableDictionary *response;
- OFString *answer;
- XMPPIQ *tuneIQ;
- OFXMLElement *pubsub, *publish, *item, *tune;
-
- tuneIQ = [XMPPIQ IQWithType: @"set"
- ID: [object generateStanzaID]];
- pubsub = [OFXMLElement elementWithName: @"pubsub"
- namespace: NS_PUBSUB];
- [tuneIQ addChild: pubsub];
- publish = [OFXMLElement elementWithName: @"publish"
- namespace: NS_PUBSUB];
- [publish addAttributeWithName: @"node"
- stringValue: NS_TUNE];
- [pubsub addChild: publish];
- item = [OFXMLElement elementWithName: @"item"
- namespace: NS_PUBSUB];
- [publish addChild: item];
- tune = [OFXMLElement elementWithName: @"tune"
- namespace: NS_TUNE];
- [item addChild: tune];
- [sock writeLine: @"status"];
- response = [self MPD_responseFromSocket: sock];
- if ([[response objectForKey: @"state"]
- isEqual: @"play"]) {
- [sock writeLine: @"currentsong"];
- response = [self MPD_responseFromSocket: sock];
- if ((answer =
- [response objectForKey: @"Artist"]))
- [tune addChild: [OFXMLElement
- elementWithName: @"artist"
- namespace: NS_TUNE
- stringValue: answer]];
- if ((answer = [response objectForKey: @"Time"]))
- [tune addChild: [OFXMLElement
- elementWithName: @"length"
- namespace: NS_TUNE
- stringValue: answer]];
- if ((answer =
- [response objectForKey: @"Album"]))
- [tune addChild: [OFXMLElement
- elementWithName: @"source"
- namespace: NS_TUNE
- stringValue: answer]];
- if ((answer =
- [response objectForKey: @"Title"]))
- [tune addChild: [OFXMLElement
- elementWithName: @"title"
- namespace: NS_TUNE
- stringValue: answer]];
- if ((answer =
- [response objectForKey: @"Track"]))
- [tune addChild: [OFXMLElement
- elementWithName: @"track"
- namespace: NS_TUNE
- stringValue: answer]];
- }
- [object sendStanza: tuneIQ];
- [sock writeLine: @"idle player"];
- [self MPD_responseFromSocket: sock];
- } @catch (id e) {
- [self MPD_connect];
- [self MPD_responseFromSocket: sock];
- [e release];
- }
- [pool release];
- }
-
- return nil;
-}
-@end
+++ /dev/null
-/*
- * Copyright (c) 2010, 2011, Jonathan Schleifer <js@webkeks.org>
- * Copyright (c) 2011, Florian Zeitz <florob@babelmonkeys.de>
- *
- * https://webkeks.org/hg/objxmpp/
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice is present in all copies.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <assert.h>
-
-#import <ObjFW/ObjFW.h>
-#import <ObjXMPP/ObjXMPP.h>
-
-#import "PEPThread.h"
-
-#define NS_DISCO_INFO @"http://jabber.org/protocol/disco#info"
-
-@interface AppDelegate: OFObject
-#ifdef OF_HAVE_OPTIONAL_PROTOCOLS
- <OFApplicationDelegate, XMPPConnectionDelegate>
-#endif
-
-OFString *discoID;
-PEPThread *pepper;
-@end
-
-OF_APPLICATION_DELEGATE(AppDelegate)
-
-@implementation AppDelegate
-- (void)applicationDidFinishLaunching
-{
- XMPPConnection *conn;
- OFArray *arguments = [OFApplication arguments];
-
- conn = [[XMPPConnection alloc] init];
- [conn setDelegate: self];
-
- if ([arguments count] != 3) {
- of_log(@"Invalid count of command line arguments!");
- [OFApplication terminateWithStatus: 1];
- }
-
- [conn setDomain: [arguments objectAtIndex: 0]];
- [conn setUsername: [arguments objectAtIndex: 1]];
- [conn setPassword: [arguments objectAtIndex: 2]];
- [conn setResource: @"ObjXMPP"];
-
- @try {
- [conn connect];
- [conn handleConnection];
- } @catch (id e) {
- of_log(@"%@", e);
- }
-}
-
-- (void)connectionWasAuthenticated: (XMPPConnection*)conn
-{
- of_log(@"Auth successful");
-}
-
-- (void)connection: (XMPPConnection*)conn
- wasBoundToJID: (XMPPJID*)jid
-{
- XMPPPresence *pres;
- XMPPIQ *disco;
-
- of_log(@"Bound to JID: %@", [jid fullJID]);
-
- pres = [XMPPPresence presence];
- [pres addPriority: 0];
- [pres addStatus: @"Hello I'm MPDbot!"];
- [conn sendStanza: pres];
-
- discoID = [[conn generateStanzaID] retain];
- disco = [XMPPIQ IQWithType: @"get"
- ID: discoID];
- disco.to = [XMPPJID JIDWithString: [[conn JID] bareJID]];
- [disco addChild: [OFXMLElement
- elementWithName: @"query"
- namespace: NS_DISCO_INFO]];
-
- [conn sendStanza: disco];
-}
-
-- (BOOL)connection: (XMPPConnection*)conn
- didReceiveIQ: (XMPPIQ*)iq
-{
- OFXMLElement *query = [iq elementForName: @"query"
- namespace: NS_DISCO_INFO];
- if ([[iq ID] isEqual: discoID]) {
- for (OFXMLElement *identity
- in [query elementsForName: @"identity"
- namespace: NS_DISCO_INFO]) {
- if ([[[identity attributeForName: @"category"]
- stringValue] isEqual: @"pubsub"] &&
- [[[identity attributeForName: @"type"] stringValue]
- isEqual: @"pep"]) {
- pepper = [[PEPThread alloc]
- initWithObject: conn];
- [pepper start];
- return YES;
- }
- }
- }
-
- return NO;
-}
-
-- (void)connection: (XMPPConnection*)conn
- didReceiveMessage: (XMPPMessage*)msg
-{
- of_log(@"Message: %@", msg);
-}
-
-- (void)connection: (XMPPConnection*)conn
- didReceivePresence: (XMPPPresence*)pres
-{
- of_log(@"Presence: %@", pres);
-}
-
-- (void)connectionWasClosed: (XMPPConnection*)conn
-{
- of_log(@"Connection was closed!");
-}
-@end
--- /dev/null
+@interface PEPThread: OFThread
+- (void)MPD_connect;
+- (OFMutableDictionary*)MPD_responseFromSocket: (OFTCPSocket*)sock;
+
+OFTCPSocket *sock;
+@end
--- /dev/null
+#import <ObjFW/ObjFW.h>
+#import <ObjXMPP/ObjXMPP.h>
+
+#import "PEPThread.h"
+
+#define NS_PUBSUB @"http://jabber.org/protocol/pubsub"
+#define NS_TUNE @"http://jabber.org/protocol/tune"
+
+@implementation PEPThread: OFThread
+- (void)dealloc
+{
+ [sock release];
+
+ [super dealloc];
+}
+
+- (void)MPD_connect
+{
+ int64_t pause = 1;
+ while(1) {
+ @try {
+ [sock release];
+ sock = [[OFTCPSocket alloc] init];
+ [sock connectToHost: @"localhost"
+ port: 6600];
+ return;
+ } @catch (id e) {
+ of_log(@"Connection failed, retrying in %" PRIi64
+ " seconds", pause);
+ [OFThread sleepForTimeInterval: pause];
+ if (pause < 120)
+ pause *= 2;
+ [e release];
+ }
+ }
+}
+
+- (OFMutableDictionary*)MPD_responseFromSocket: (OFTCPSocket*)sock
+{
+ OFString *answer;
+ OFMutableDictionary *response = [OFMutableDictionary dictionary];
+ while ((answer = [sock readLine]) && ![answer hasPrefix: @"OK"]) {
+ size_t index;
+ index = [answer indexOfFirstOccurrenceOfString: @":"];
+ if (index == OF_INVALID_INDEX)
+ continue;
+ [response setObject: [answer substringFromIndex: index + 2
+ toIndex: answer.length]
+ forKey: [answer substringFromIndex: 0
+ toIndex: index]];
+ }
+
+ return response;
+}
+
+- (id)main
+{
+ [self MPD_connect];
+ [self MPD_responseFromSocket: sock];
+ while (1) {
+ OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
+ @try {
+ OFMutableDictionary *response;
+ OFString *answer;
+ XMPPIQ *tuneIQ;
+ OFXMLElement *pubsub, *publish, *item, *tune;
+
+ tuneIQ = [XMPPIQ IQWithType: @"set"
+ ID: [object generateStanzaID]];
+ pubsub = [OFXMLElement elementWithName: @"pubsub"
+ namespace: NS_PUBSUB];
+ [tuneIQ addChild: pubsub];
+ publish = [OFXMLElement elementWithName: @"publish"
+ namespace: NS_PUBSUB];
+ [publish addAttributeWithName: @"node"
+ stringValue: NS_TUNE];
+ [pubsub addChild: publish];
+ item = [OFXMLElement elementWithName: @"item"
+ namespace: NS_PUBSUB];
+ [publish addChild: item];
+ tune = [OFXMLElement elementWithName: @"tune"
+ namespace: NS_TUNE];
+ [item addChild: tune];
+ [sock writeLine: @"status"];
+ response = [self MPD_responseFromSocket: sock];
+ if ([[response objectForKey: @"state"]
+ isEqual: @"play"]) {
+ [sock writeLine: @"currentsong"];
+ response = [self MPD_responseFromSocket: sock];
+ if ((answer =
+ [response objectForKey: @"Artist"]))
+ [tune addChild: [OFXMLElement
+ elementWithName: @"artist"
+ namespace: NS_TUNE
+ stringValue: answer]];
+ if ((answer = [response objectForKey: @"Time"]))
+ [tune addChild: [OFXMLElement
+ elementWithName: @"length"
+ namespace: NS_TUNE
+ stringValue: answer]];
+ if ((answer =
+ [response objectForKey: @"Album"]))
+ [tune addChild: [OFXMLElement
+ elementWithName: @"source"
+ namespace: NS_TUNE
+ stringValue: answer]];
+ if ((answer =
+ [response objectForKey: @"Title"]))
+ [tune addChild: [OFXMLElement
+ elementWithName: @"title"
+ namespace: NS_TUNE
+ stringValue: answer]];
+ if ((answer =
+ [response objectForKey: @"Track"]))
+ [tune addChild: [OFXMLElement
+ elementWithName: @"track"
+ namespace: NS_TUNE
+ stringValue: answer]];
+ }
+ [object sendStanza: tuneIQ];
+ [sock writeLine: @"idle player"];
+ [self MPD_responseFromSocket: sock];
+ } @catch (id e) {
+ [self MPD_connect];
+ [self MPD_responseFromSocket: sock];
+ [e release];
+ }
+ [pool release];
+ }
+
+ return nil;
+}
+@end
--- /dev/null
+/*
+ * Copyright (c) 2010, 2011, Jonathan Schleifer <js@webkeks.org>
+ * Copyright (c) 2011, Florian Zeitz <florob@babelmonkeys.de>
+ *
+ * https://webkeks.org/hg/objxmpp/
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+#import <ObjFW/ObjFW.h>
+#import <ObjXMPP/ObjXMPP.h>
+
+#import "PEPThread.h"
+
+#define NS_DISCO_INFO @"http://jabber.org/protocol/disco#info"
+
+@interface AppDelegate: OFObject
+#ifdef OF_HAVE_OPTIONAL_PROTOCOLS
+ <OFApplicationDelegate, XMPPConnectionDelegate>
+#endif
+
+OFString *discoID;
+PEPThread *pepper;
+@end
+
+OF_APPLICATION_DELEGATE(AppDelegate)
+
+@implementation AppDelegate
+- (void)applicationDidFinishLaunching
+{
+ XMPPConnection *conn;
+ OFArray *arguments = [OFApplication arguments];
+
+ conn = [[XMPPConnection alloc] init];
+ [conn setDelegate: self];
+
+ if ([arguments count] != 3) {
+ of_log(@"Invalid count of command line arguments!");
+ [OFApplication terminateWithStatus: 1];
+ }
+
+ [conn setDomain: [arguments objectAtIndex: 0]];
+ [conn setUsername: [arguments objectAtIndex: 1]];
+ [conn setPassword: [arguments objectAtIndex: 2]];
+ [conn setResource: @"ObjXMPP"];
+
+ @try {
+ [conn connect];
+ [conn handleConnection];
+ } @catch (id e) {
+ of_log(@"%@", e);
+ }
+}
+
+- (void)connectionWasAuthenticated: (XMPPConnection*)conn
+{
+ of_log(@"Auth successful");
+}
+
+- (void)connection: (XMPPConnection*)conn
+ wasBoundToJID: (XMPPJID*)jid
+{
+ XMPPPresence *pres;
+ XMPPIQ *disco;
+
+ of_log(@"Bound to JID: %@", [jid fullJID]);
+
+ pres = [XMPPPresence presence];
+ [pres addPriority: 0];
+ [pres addStatus: @"Hello I'm MPDbot!"];
+ [conn sendStanza: pres];
+
+ discoID = [[conn generateStanzaID] retain];
+ disco = [XMPPIQ IQWithType: @"get"
+ ID: discoID];
+ disco.to = [XMPPJID JIDWithString: [[conn JID] bareJID]];
+ [disco addChild: [OFXMLElement
+ elementWithName: @"query"
+ namespace: NS_DISCO_INFO]];
+
+ [conn sendStanza: disco];
+}
+
+- (BOOL)connection: (XMPPConnection*)conn
+ didReceiveIQ: (XMPPIQ*)iq
+{
+ OFXMLElement *query = [iq elementForName: @"query"
+ namespace: NS_DISCO_INFO];
+ if ([[iq ID] isEqual: discoID]) {
+ for (OFXMLElement *identity
+ in [query elementsForName: @"identity"
+ namespace: NS_DISCO_INFO]) {
+ if ([[[identity attributeForName: @"category"]
+ stringValue] isEqual: @"pubsub"] &&
+ [[[identity attributeForName: @"type"] stringValue]
+ isEqual: @"pep"]) {
+ pepper = [[PEPThread alloc]
+ initWithObject: conn];
+ [pepper start];
+ return YES;
+ }
+ }
+ }
+
+ return NO;
+}
+
+- (void)connection: (XMPPConnection*)conn
+ didReceiveMessage: (XMPPMessage*)msg
+{
+ of_log(@"Message: %@", msg);
+}
+
+- (void)connection: (XMPPConnection*)conn
+ didReceivePresence: (XMPPPresence*)pres
+{
+ of_log(@"Presence: %@", pres);
+}
+
+- (void)connectionWasClosed: (XMPPConnection*)conn
+{
+ of_log(@"Connection was closed!");
+}
+@end