]> cgit.babelmonkeys.de Git - mpdbot.git/blob - src/PEPThread.m
Support MPD_HOST/MPD_PORT environment variables
[mpdbot.git] / src / PEPThread.m
1 /*
2  * Copyright (c) 2011, Florian Zeitz <florob@babelmonkeys.de>
3  *
4  * http://cgit.babelmonkeys.de/cgit.cgi/mpdbot/
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice is present in all copies.
9  *
10  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
11  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
14  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
15  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
16  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
17  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
18  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
20  * POSSIBILITY OF SUCH DAMAGE.
21  */
22
23 #import <ObjFW/ObjFW.h>
24 #import <ObjXMPP/ObjXMPP.h>
25
26 #import "PEPThread.h"
27
28 #define NS_PUBSUB @"http://jabber.org/protocol/pubsub"
29 #define NS_TUNE @"http://jabber.org/protocol/tune"
30
31 @implementation PEPThread: OFThread
32 - (void)dealloc
33 {
34         [sock release];
35
36         [super dealloc];
37 }
38
39 - (void)MPD_connect
40 {
41         int64_t pause = 1;
42         while(1) {
43                 @try {
44                         [sock release];
45                         sock = [[OFTCPSocket alloc] init];
46                         [sock connectToHost: mpd_host
47                                        port: mpd_port];
48                         return;
49                 } @catch (id e) {
50                         [of_stderr writeFormat: @"Connection failed, retrying"
51                                 @" in %" PRIi64 @" seconds\n", pause];
52                         [OFThread sleepForTimeInterval: pause];
53                         if (pause < 120)
54                                 pause *= 2;
55                         [e release];
56                 }
57         }
58 }
59
60 - (OFMutableDictionary*)MPD_responseFromSocket: (OFTCPSocket*)sock_
61 {
62         OFString *answer;
63         OFMutableDictionary *response = [OFMutableDictionary dictionary];
64         while ((answer = [sock_ readLine]) && ![answer hasPrefix: @"OK"]) {
65                 size_t index;
66                 index = [answer indexOfFirstOccurrenceOfString: @":"];
67                 if (index == OF_INVALID_INDEX)
68                         continue;
69                 [response setObject: [answer substringFromIndex: index + 2
70                                                         toIndex: answer.length]
71                              forKey: [answer substringFromIndex: 0
72                                                         toIndex: index]];
73         }
74
75         return response;
76 }
77
78 - (id)main
79 {
80         OFDictionary *environment = [OFApplication environment];
81         OFString *mpd_port_string;
82         mpd_host = [environment objectForKey: @"MPD_HOST"];
83         if (mpd_host == nil)
84                 mpd_host = @"localhost";
85         mpd_port_string = [environment objectForKey: @"MPD_PORT"];
86         if (mpd_port_string && [mpd_port_string decimalValue] <= UINT16_MAX)
87                 mpd_port = (uint16_t) [mpd_port_string decimalValue];
88         else
89                 mpd_port = 6600;
90         [self MPD_connect];
91         [self MPD_responseFromSocket: sock];
92         while (1) {
93                 OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
94                 @try {
95                         OFMutableDictionary *response;
96                         OFString *answer;
97                         XMPPIQ *tuneIQ;
98                         OFXMLElement *pubsub, *publish, *item, *tune;
99
100                         tuneIQ = [XMPPIQ IQWithType: @"set"
101                                                  ID: [object generateStanzaID]];
102                         pubsub = [OFXMLElement elementWithName: @"pubsub"
103                                                      namespace: NS_PUBSUB];
104                         [tuneIQ addChild: pubsub];
105                         publish = [OFXMLElement elementWithName: @"publish"
106                                                       namespace: NS_PUBSUB];
107                         [publish addAttributeWithName: @"node"
108                                           stringValue: NS_TUNE];
109                         [pubsub addChild: publish];
110                         item = [OFXMLElement elementWithName: @"item"
111                                                    namespace: NS_PUBSUB];
112                         [publish addChild: item];
113                         tune = [OFXMLElement elementWithName: @"tune"
114                                                    namespace: NS_TUNE];
115                         [item addChild: tune];
116                         [sock writeLine: @"status"];
117                         response = [self MPD_responseFromSocket: sock];
118                         if ([[response objectForKey: @"state"]
119                             isEqual: @"play"]) {
120                                 [sock writeLine: @"currentsong"];
121                                 response = [self MPD_responseFromSocket: sock];
122                                 if ((answer =
123                                     [response objectForKey: @"Artist"]))
124                                         [tune addChild: [OFXMLElement
125                                             elementWithName: @"artist"
126                                                   namespace: NS_TUNE
127                                                 stringValue: answer]];
128                                 if ((answer = [response objectForKey: @"Time"]))
129                                         [tune addChild: [OFXMLElement
130                                             elementWithName: @"length"
131                                                   namespace: NS_TUNE
132                                                 stringValue: answer]];
133                                 if ((answer =
134                                     [response objectForKey: @"Album"]))
135                                         [tune addChild: [OFXMLElement
136                                             elementWithName: @"source"
137                                                   namespace: NS_TUNE
138                                                 stringValue: answer]];
139                                 if ((answer =
140                                     [response objectForKey: @"Title"]))
141                                         [tune addChild: [OFXMLElement
142                                             elementWithName: @"title"
143                                                   namespace: NS_TUNE
144                                                 stringValue: answer]];
145                                 if ((answer =
146                                     [response objectForKey: @"Track"]))
147                                         [tune addChild: [OFXMLElement
148                                             elementWithName: @"track"
149                                                   namespace: NS_TUNE
150                                                 stringValue: answer]];
151                         }
152                         [object sendStanza: tuneIQ];
153                         [sock writeLine: @"idle player"];
154                         [self MPD_responseFromSocket: sock];
155                 } @catch (id e) {
156                         [self MPD_connect];
157                         [self MPD_responseFromSocket: sock];
158                         [e release];
159                 }
160                 [pool release];
161         }
162
163         return nil;
164 }
165 @end