reset handshake only if it is reasonable
[scrobby.git] / src / scrobby.cpp
blob32afe3077e37e044412744233794e3e182813d9c
1 /***************************************************************************
2 * Copyright (C) 2008 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include <csignal>
22 #include <cstdlib>
23 #include <curl/curl.h>
24 #include <iostream>
25 #include <vector>
27 #include "callback.h"
28 #include "configuration.h"
29 #include "misc.h"
30 #include "scrobby.h"
31 #include "song.h"
32 #include "mpdpp.h"
34 using std::string;
36 Handshake myHandshake;
37 MPD::Song s;
39 namespace
41 void do_at_exit();
42 void signal_handler(int);
44 bool handshake_sent_properly();
47 int main(int argc, char **argv)
49 DefaultConfiguration(Config);
51 if (argc > 1)
53 ParseArgv(Config, argc, argv);
55 if (!Config.file_config.empty())
57 if (!ReadConfiguration(Config, Config.file_config))
59 std::cerr << "cannot read configuration file: " << Config.file_config << std::endl;
60 return 1;
63 else if (!ReadConfiguration(Config, Config.user_home_folder + "/.scrobbyconf"))
65 if (!ReadConfiguration(Config, "/etc/scrobby.conf"))
67 std::cerr << "default configuration files not found!\n";
68 return 1;
71 if (Config.log_level == llUndefined)
73 Config.log_level = llInfo;
75 if (Config.lastfm_user.empty() || (Config.lastfm_md5_password.empty() && Config.lastfm_password.empty()))
77 std::cerr << "last.fm user/password is not set.\n";
78 return 1;
80 ChangeToUser();
81 if (!CheckFiles(Config))
83 return 1;
85 if (Config.daemonize)
87 if (!Daemonize())
88 std::cerr << "couldn't daemonize!\n";
91 MPD::Song::GetCached();
93 MPD::Connection *Mpd = new MPD::Connection;
95 if (Config.mpd_host != "localhost")
96 Mpd->SetHostname(Config.mpd_host);
97 if (Config.mpd_port != 6600)
98 Mpd->SetPort(Config.mpd_port);
100 Mpd->SetTimeout(Config.mpd_timeout);
101 Mpd->SetStatusUpdater(ScrobbyStatusChanged, NULL);
102 Mpd->SetErrorHandler(ScrobbyErrorCallback, NULL);
104 signal(SIGHUP, signal_handler);
105 signal(SIGINT, signal_handler);
106 signal(SIGTERM, signal_handler);
107 signal(SIGPIPE, SIG_IGN);
109 atexit(do_at_exit);
111 int handshake_delay = 0;
112 int mpd_delay = 0;
114 time_t now = 0;
115 time_t handshake_ts = 0;
116 time_t mpd_ts = 0;
118 while (!usleep(500000))
120 time(&now);
121 if (now > handshake_ts && myHandshake.Status != "OK")
123 myHandshake.Clear();
124 if (handshake_sent_properly() && !myHandshake.Status.empty())
126 Log(llInfo, "Handshake returned %s", myHandshake.Status.c_str());
128 if (myHandshake.Status == "OK")
130 Log(llInfo, "Connected to Audioscrobbler!");
131 handshake_delay = 0;
133 else
135 handshake_delay += 10;
136 Log(llInfo, "Connection to Audioscrobbler refused, retrieving in %d seconds...", handshake_delay);
137 handshake_ts = time(0)+handshake_delay;
140 if (Mpd->Connected())
142 Mpd->UpdateStatus();
144 else if (now > mpd_ts)
146 s.Submit();
147 Log(llVerbose, "Connecting to MPD...");
148 if (Mpd->Connect())
150 Log(llInfo, "Connected to MPD at %s !", Config.mpd_host.c_str());
151 mpd_delay = 0;
153 else
155 mpd_delay += 10;
156 Log(llInfo, "Cannot connect to MPD, retrieving in %d seconds...", mpd_delay);
157 mpd_ts = time(0)+mpd_delay;
161 return 0;
164 namespace
166 void do_at_exit()
168 s.Submit();
169 Log(llInfo, "Shutting down...");
170 if (remove(Config.file_pid.c_str()) != 0)
171 Log(llInfo, "Couldn't remove pid file!");
174 void signal_handler(int)
176 exit(0);
179 bool handshake_sent_properly()
181 CURLcode code;
182 string handshake_url;
183 string result;
184 string timestamp = IntoStr(time(NULL));
186 handshake_url = "http://post.audioscrobbler.com/?hs=true&p=1.2.1&c=mpc&v="VERSION"&u=";
187 handshake_url += Config.lastfm_user;
188 handshake_url += "&t=";
189 handshake_url += timestamp;
190 handshake_url += "&a=";
191 handshake_url += md5sum((Config.lastfm_md5_password.empty() ? md5sum(Config.lastfm_password) : Config.lastfm_md5_password) + timestamp);
193 CURL *hs = curl_easy_init();
194 curl_easy_setopt(hs, CURLOPT_URL, handshake_url.c_str());
195 curl_easy_setopt(hs, CURLOPT_WRITEFUNCTION, write_data);
196 curl_easy_setopt(hs, CURLOPT_WRITEDATA, &result);
197 curl_easy_setopt(hs, CURLOPT_CONNECTTIMEOUT, curl_timeout);
198 code = curl_easy_perform(hs);
199 curl_easy_cleanup(hs);
201 if (code != CURLE_OK)
203 Log(llInfo, "Error while sending handshake: %s", curl_easy_strerror(code));
204 return false;
207 size_t i = result.find("\n");
208 myHandshake.Status = result.substr(0, i);
209 if (myHandshake.Status != "OK")
210 return false;
211 result = result.substr(i+1);
212 i = result.find("\n");
213 myHandshake.SessionID = result.substr(0, i);
214 result = result.substr(i+1);
215 i = result.find("\n");
216 myHandshake.NowPlayingURL = result.substr(0, i);
217 result = result.substr(i+1);
218 IgnoreNewlines(result);
219 myHandshake.SubmissionURL = result;
220 return true;