File indexing completed on 2025-01-05 04:27:01
0001 /* 0002 * Copyright (C) 2008 MP3tunes, LLC 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public 0015 * License along with this library; if not, write to the Free Software 0016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 0017 */ 0018 0019 #include <unistd.h> 0020 #include <stdio.h> 0021 #include <stdlib.h> 0022 #include <string.h> 0023 #include "harmony.h" 0024 0025 G_DEFINE_TYPE(MP3tunesHarmony, mp3tunes_harmony, G_TYPE_OBJECT); 0026 0027 char *str_replace(const char *search, const char *replace, char *subject); 0028 gboolean harmony_format_email(char **email); 0029 0030 void state_change_emit(MP3tunesHarmony *harmony, guint32 state); 0031 void error_emit(MP3tunesHarmony *harmony, gint code, const gchar* message, GError* err); 0032 0033 LmHandlerResult harmony_download_callback(LmMessageHandler* handler, LmConnection *connection, LmMessage *message, gpointer void_harmony); 0034 0035 LmHandlerResult harmony_get_device_pin_callback(LmMessageHandler* handler, LmConnection *connection, LmMessage *message, gpointer void_harmony); 0036 void harmony_get_device_pin(MP3tunesHarmony *harmony); 0037 0038 LmHandlerResult harmony_get_device_email_callback(LmMessageHandler* handler, LmConnection *connection, LmMessage *message, gpointer void_harmony); 0039 void harmony_get_device_email(MP3tunesHarmony *harmony); 0040 0041 void authenticate_known_callback(LmConnection* connection, gboolean success, gpointer void_harmony); 0042 void authenticate_new_callback(LmConnection* connection, gboolean success, gpointer void_harmony); 0043 void authenticate_unknown_callback(LmConnection* connection, gboolean success, gpointer void_harmony); 0044 0045 void rebuild_connection(MP3tunesHarmony* harmony); 0046 0047 void open_connection_callback(LmConnection* connection, gboolean success, gpointer void_harmony); 0048 gboolean open_connection(MP3tunesHarmony *harmony); 0049 0050 gboolean close_connection(MP3tunesHarmony *harmony); 0051 0052 char *str_replace(const char *search, const char *replace, char *subject) { 0053 char *result, *tmp, *needle; 0054 int count, length; 0055 0056 length = strlen(subject); 0057 if (strlen(search) < strlen(replace)) { 0058 /* We need to increase the buffer size for result a bit */ 0059 count = 0; 0060 tmp = subject; 0061 0062 while((needle = strstr(tmp, search))) { 0063 tmp = needle + strlen(search); 0064 count++; 0065 } 0066 0067 length += (strlen(replace) - strlen(search)) * count; 0068 } 0069 0070 result = (char *)malloc(sizeof(char)*(length+1)); 0071 memset(result, 0, sizeof(char) * (length + 1)); 0072 0073 tmp = subject; 0074 while((needle = strstr(tmp, search))) { 0075 length = needle-tmp; /* Length from current index in buffer to a match */ 0076 strncat(result, tmp, length); /* put normal (unreplaced) string data into the new buffer */ 0077 strcat(result, replace); /* then the replacement */ 0078 tmp = needle + strlen(search); /* Jump past the replaced text and continue */ 0079 } 0080 0081 strcat(result, tmp); /* remaining data after the last match */ 0082 return result; 0083 } 0084 0085 gboolean harmony_format_email(char **email) { 0086 char *tmp; 0087 char *tmp_two; 0088 0089 if (*email == NULL) return FALSE; 0090 0091 tmp = str_replace("@", "_AT_", *email); 0092 free(*email); 0093 0094 tmp_two = str_replace(".", "_DOT_", tmp); 0095 free(tmp); 0096 0097 *email = tmp_two; 0098 0099 return TRUE; 0100 } 0101 0102 void state_change_emit(MP3tunesHarmony *harmony, guint32 state) { 0103 g_signal_emit(harmony, MP3TUNES_HARMONY_GET_CLASS(harmony)->state_change_signal_id, 0, state); 0104 } 0105 0106 void error_emit(MP3tunesHarmony *harmony, gint code, const gchar* message, GError* err) { 0107 if (err) { 0108 g_propagate_error(&harmony->error, g_error_new(MP3TUNES_HARMONY_ERROR_DOMAIN, code, "%s: %s", message, err->message)); 0109 } else { 0110 g_propagate_error(&harmony->error, g_error_new(MP3TUNES_HARMONY_ERROR_DOMAIN, code, "%s", message)); 0111 } 0112 g_signal_emit(harmony, MP3TUNES_HARMONY_GET_CLASS(harmony)->error_signal_id, 0); 0113 } 0114 0115 void download_pending_emit(MP3tunesHarmony *harmony, mp3tunes_harmony_download_t* harmony_download) { 0116 g_print("Signal ID: %d, Download: %p\n", MP3TUNES_HARMONY_GET_CLASS(harmony)->download_pending_signal_id, harmony_download); 0117 g_signal_emit(harmony, MP3TUNES_HARMONY_GET_CLASS(harmony)->download_pending_signal_id, 0, harmony_download); 0118 } 0119 0120 void download_ready_emit(MP3tunesHarmony *harmony, mp3tunes_harmony_download_t* harmony_download) { 0121 g_print("Signal ID: %d, Download: %p\n", MP3TUNES_HARMONY_GET_CLASS(harmony)->download_ready_signal_id, harmony_download); 0122 g_signal_emit(harmony, MP3TUNES_HARMONY_GET_CLASS(harmony)->download_ready_signal_id, 0, harmony_download); 0123 } 0124 0125 gboolean mp3tunes_harmony_download_init(mp3tunes_harmony_download_t **harmony_download) { 0126 mp3tunes_harmony_download_t* hd = *harmony_download = malloc(sizeof(mp3tunes_harmony_download_t)); 0127 if (hd == NULL) { return FALSE; } 0128 hd->file_key = NULL; 0129 hd->file_name = NULL; 0130 hd->file_format = NULL; 0131 hd->file_size = 0; 0132 hd->artist_name = NULL; 0133 hd->album_title = NULL; 0134 hd->track_title = NULL; 0135 hd->track_number = 0; 0136 hd->device_bitrate = NULL; 0137 hd->file_bitrate = NULL; 0138 hd->url = NULL; 0139 return TRUE; 0140 } 0141 0142 gboolean mp3tunes_harmony_download_deinit(mp3tunes_harmony_download_t **harmony_download) { 0143 mp3tunes_harmony_download_t* hd = *harmony_download; 0144 if (hd->file_key) { free(hd->file_key); } 0145 if (hd->file_name) { free(hd->file_name); } 0146 if (hd->file_format) { free(hd->file_format); } 0147 0148 if (hd->artist_name) { free(hd->artist_name); } 0149 if (hd->album_title) { free(hd->album_title); } 0150 if (hd->track_title) { free(hd->track_title); } 0151 0152 if (hd->device_bitrate) { free(hd->device_bitrate); } 0153 if (hd->file_bitrate) { free(hd->file_bitrate); } 0154 0155 if (hd->url) { free(hd->url); } 0156 free(hd); 0157 return TRUE; 0158 } 0159 0160 void mp3tunes_harmony_download_set_file_key(mp3tunes_harmony_download_t *harmony_download, char* file_key) { 0161 harmony_download->file_key = strdup(file_key); 0162 } 0163 0164 void mp3tunes_harmony_download_set_file_name(mp3tunes_harmony_download_t *harmony_download, char* file_name) { 0165 harmony_download->file_name = strdup(file_name); 0166 } 0167 0168 void mp3tunes_harmony_download_set_file_format(mp3tunes_harmony_download_t *harmony_download, char* file_format) { 0169 harmony_download->file_format = strdup(file_format); 0170 } 0171 0172 void mp3tunes_harmony_download_set_file_size(mp3tunes_harmony_download_t *harmony_download, unsigned int file_size) { 0173 harmony_download->file_size = file_size; 0174 } 0175 0176 void mp3tunes_harmony_download_set_artist_name(mp3tunes_harmony_download_t *harmony_download, char* artist_name) { 0177 harmony_download->artist_name = strdup(artist_name); 0178 } 0179 0180 void mp3tunes_harmony_download_set_album_title(mp3tunes_harmony_download_t *harmony_download, char* album_title) { 0181 harmony_download->album_title = strdup(album_title); 0182 } 0183 0184 void mp3tunes_harmony_download_set_track_title(mp3tunes_harmony_download_t *harmony_download, char* track_title) { 0185 harmony_download->track_title = strdup(track_title); 0186 } 0187 0188 void mp3tunes_harmony_download_set_track_number(mp3tunes_harmony_download_t *harmony_download, int track_number) { 0189 harmony_download->track_number = track_number; 0190 } 0191 0192 void mp3tunes_harmony_download_set_device_bitrate(mp3tunes_harmony_download_t *harmony_download, char* device_bitrate) { 0193 if (device_bitrate) { 0194 harmony_download->device_bitrate = strdup(device_bitrate); 0195 } 0196 } 0197 0198 void mp3tunes_harmony_download_set_file_bitrate(mp3tunes_harmony_download_t *harmony_download, char* file_bitrate) { 0199 if (file_bitrate) { 0200 harmony_download->file_bitrate = strdup(file_bitrate); 0201 } 0202 } 0203 0204 void mp3tunes_harmony_download_set_url_using_locker(mp3tunes_harmony_download_t *harmony_download, mp3tunes_locker_object_t* mp3tunes_locker) { 0205 if ((harmony_download->device_bitrate == NULL) || (atoi(harmony_download->device_bitrate)) == 0) { 0206 harmony_download->url = mp3tunes_locker_generate_download_url_from_file_key(mp3tunes_locker, harmony_download->file_key); 0207 } else { 0208 harmony_download->url = mp3tunes_locker_generate_download_url_from_file_key_and_bitrate(mp3tunes_locker, harmony_download->file_key, harmony_download->device_bitrate); 0209 } 0210 } 0211 0212 void harmony_reprocess_queue(MP3tunesHarmony *harmony) { 0213 mp3tunes_harmony_download_t *harmony_download = g_queue_peek_head(harmony->download_queue); 0214 while (harmony_download != NULL && harmony->sid_state == MP3TUNES_HARMONY_SID_STATE_READY) { 0215 harmony_download = g_queue_pop_head(harmony->download_queue); 0216 mp3tunes_harmony_download_set_url_using_locker(harmony_download, harmony->mp3tunes_locker); 0217 download_ready_emit(harmony, harmony_download); 0218 harmony_download = g_queue_peek_head(harmony->download_queue); 0219 } 0220 } 0221 0222 LmHandlerResult harmony_get_session_id_callback(LmMessageHandler* handler, LmConnection *connection, LmMessage *message, gpointer void_harmony) { 0223 char *session_id; 0224 MP3tunesHarmony *harmony = MP3TUNES_HARMONY(void_harmony); 0225 LmMessageNode *harmony_session_node; 0226 0227 (void)handler; 0228 (void)connection; 0229 0230 harmony_session_node = lm_message_node_get_child(message->node, "sessionId"); 0231 if (harmony_session_node) { 0232 session_id = g_strdup(lm_message_node_get_value(harmony_session_node)); 0233 harmony->mp3tunes_locker->session_id = session_id; 0234 harmony->sid_state = MP3TUNES_HARMONY_SID_STATE_READY; 0235 0236 harmony_reprocess_queue(harmony); 0237 return LM_HANDLER_RESULT_REMOVE_MESSAGE; 0238 } 0239 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; 0240 } 0241 0242 void harmony_get_session_id(MP3tunesHarmony *harmony) { 0243 LmMessage *message_out; 0244 LmMessageHandler *handler; 0245 LmMessageNode *message_out_node; 0246 GError *err = NULL; 0247 handler = lm_message_handler_new(harmony_get_session_id_callback, (gpointer)harmony, NULL); 0248 0249 message_out = lm_message_new(MP3TUNES_HARMONY_CONDUCTOR, LM_MESSAGE_TYPE_IQ); 0250 message_out_node = lm_message_node_add_child(message_out->node, "sessionId", NULL); 0251 lm_message_node_set_attribute(message_out_node, "xmlns", MP3TUNES_HARMONY_XMLNS); 0252 0253 lm_connection_send_with_reply(harmony->connection, 0254 message_out, 0255 handler, 0256 &err); 0257 lm_message_unref(message_out); 0258 if (err != NULL) { 0259 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending session id request failed", err); 0260 return; 0261 } 0262 harmony->sid_state = MP3TUNES_HARMONY_SID_STATE_WAITING; 0263 } 0264 0265 mp3tunes_harmony_download_t* mp3tunes_harmony_download_queue_pop(MP3tunesHarmony *harmony) { 0266 if (harmony->sid_state != MP3TUNES_HARMONY_SID_STATE_READY) { 0267 return NULL; 0268 } 0269 return (mp3tunes_harmony_download_t*)g_queue_pop_head(harmony->download_queue); 0270 } 0271 0272 void mp3tunes_harmony_download_failed(MP3tunesHarmony* harmony, mp3tunes_harmony_download_t* harmony_download) { 0273 harmony->mp3tunes_locker->session_id = NULL; 0274 harmony->sid_state = MP3TUNES_HARMONY_SID_STATE_NONE; 0275 g_queue_push_head(harmony->download_queue, harmony_download); 0276 if (harmony->sid_state == MP3TUNES_HARMONY_SID_STATE_READY) { 0277 harmony_get_session_id(harmony); 0278 } 0279 } 0280 0281 void mp3tunes_harmony_download_cancel(MP3tunesHarmony* harmony, mp3tunes_harmony_download_t* harmony_download) { 0282 g_queue_remove(harmony->download_queue, harmony_download); 0283 } 0284 0285 void mp3tunes_harmony_add_download_to_queue(MP3tunesHarmony *harmony, mp3tunes_harmony_download_t* harmony_download) { 0286 g_queue_push_tail(harmony->download_queue, harmony_download); 0287 if (harmony->sid_state == MP3TUNES_HARMONY_SID_STATE_NONE) { 0288 harmony_get_session_id(harmony); 0289 } else if (harmony->sid_state == MP3TUNES_HARMONY_SID_STATE_READY) { 0290 harmony_download->url = mp3tunes_locker_generate_download_url_from_file_key(harmony->mp3tunes_locker, harmony_download->file_key); 0291 download_ready_emit(harmony, harmony_download); 0292 } 0293 } 0294 0295 void harmony_success_reply(LmConnection *connection, LmMessage *message, GError **err) { 0296 LmMessage *message_out; 0297 LmMessageNode *harmony_download_node; 0298 LmMessageNode *message_out_node; 0299 0300 message_out = lm_message_new_with_sub_type(MP3TUNES_HARMONY_CONDUCTOR, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_RESULT); 0301 lm_message_node_set_attribute(message_out->node, "id", lm_message_node_get_attribute(message->node, "id")); 0302 message_out_node = lm_message_node_add_child(message_out->node, "success", NULL); 0303 0304 harmony_download_node = lm_message_node_get_child(message->node, "download"); 0305 if (harmony_download_node) { 0306 lm_message_node_set_attribute(message_out_node, "messageId", lm_message_node_get_attribute(harmony_download_node, "messageId")); 0307 } 0308 lm_message_node_set_attribute(message_out_node, "xmlns", MP3TUNES_HARMONY_XMLNS); 0309 0310 lm_connection_send(connection, message_out, err); 0311 lm_message_unref(message_out); 0312 } 0313 0314 LmHandlerResult harmony_iq_callback(LmMessageHandler* handler, LmConnection *connection, LmMessage *message, gpointer void_harmony) { 0315 GError *err = NULL; 0316 MP3tunesHarmony *harmony = MP3TUNES_HARMONY(void_harmony); 0317 LmMessageNode *harmony_download_node, *harmony_email_node; 0318 0319 mp3tunes_harmony_download_t *download; 0320 gchar *email; 0321 0322 (void)handler; 0323 0324 harmony_download_node = lm_message_node_get_child(message->node, "download"); 0325 if (harmony_download_node) { 0326 mp3tunes_harmony_download_init(&download); 0327 mp3tunes_harmony_download_set_file_key(download, (char*)lm_message_node_get_attribute(harmony_download_node, "fileKey")); 0328 mp3tunes_harmony_download_set_file_name(download, (char*)lm_message_node_get_attribute(harmony_download_node, "fileName")); 0329 mp3tunes_harmony_download_set_file_format(download, (char*)lm_message_node_get_attribute(harmony_download_node, "fileFormat")); 0330 mp3tunes_harmony_download_set_file_size(download, atoi(lm_message_node_get_attribute(harmony_download_node, "fileSize"))); 0331 mp3tunes_harmony_download_set_track_title(download, (char*)lm_message_node_get_attribute(harmony_download_node, "trackTitle")); 0332 mp3tunes_harmony_download_set_artist_name(download, (char*)lm_message_node_get_attribute(harmony_download_node, "artistName")); 0333 mp3tunes_harmony_download_set_album_title(download, (char*)lm_message_node_get_attribute(harmony_download_node, "albumTitle")); 0334 mp3tunes_harmony_download_set_device_bitrate(download, (char*)lm_message_node_get_attribute(harmony_download_node, "deviceBitrate")); 0335 mp3tunes_harmony_download_set_file_bitrate(download, (char*)lm_message_node_get_attribute(harmony_download_node, "fileBitrate")); 0336 0337 download_pending_emit(harmony, download); 0338 0339 mp3tunes_harmony_add_download_to_queue(harmony, download); 0340 0341 harmony_success_reply(connection, message, &err); 0342 0343 if (err != NULL) { 0344 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending success reply failed", err); 0345 } 0346 return LM_HANDLER_RESULT_REMOVE_MESSAGE; 0347 } 0348 0349 harmony_email_node = lm_message_node_get_child(message->node, "email"); 0350 if (harmony_email_node) { 0351 email = g_strdup(lm_message_node_get_value(harmony_email_node)); 0352 mp3tunes_harmony_set_email(harmony, email); 0353 g_free(email); 0354 harmony_success_reply(connection, message, &err); 0355 if (err != NULL) { 0356 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending success reply failed", err); 0357 } 0358 close_connection(harmony); 0359 open_connection(harmony); 0360 return LM_HANDLER_RESULT_REMOVE_MESSAGE; 0361 } 0362 0363 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; 0364 } 0365 0366 LmHandlerResult harmony_get_device_pin_callback(LmMessageHandler* handler, LmConnection *connection, LmMessage *message, gpointer void_harmony) { 0367 char *pin; 0368 MP3tunesHarmony *harmony = MP3TUNES_HARMONY(void_harmony); 0369 LmMessageNode *harmony_pin_node; 0370 0371 (void)handler; 0372 (void)connection; 0373 0374 harmony_pin_node = lm_message_node_get_child(message->node, "pin"); 0375 if (harmony_pin_node) { 0376 pin = g_strdup(lm_message_node_get_value(harmony_pin_node)); 0377 mp3tunes_harmony_set_pin(harmony, pin); 0378 g_free(pin); 0379 close_connection(harmony); 0380 open_connection(harmony); 0381 return LM_HANDLER_RESULT_REMOVE_MESSAGE; 0382 } 0383 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; 0384 } 0385 0386 void harmony_get_device_pin(MP3tunesHarmony *harmony) { 0387 LmMessage *message_out; 0388 LmMessageNode *message_out_node; 0389 LmMessageHandler *handler; 0390 GError *err = NULL; 0391 handler = lm_message_handler_new(harmony_get_device_pin_callback, (gpointer)harmony, NULL); 0392 0393 message_out = lm_message_new_with_sub_type(MP3TUNES_HARMONY_CONDUCTOR, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); 0394 message_out_node = lm_message_node_add_child(message_out->node, "pin", NULL); 0395 lm_message_node_set_attribute(message_out_node, "xmlns", MP3TUNES_HARMONY_XMLNS); 0396 0397 lm_connection_send_with_reply(harmony->connection, 0398 message_out, 0399 handler, 0400 &err); 0401 lm_message_unref(message_out); 0402 if (err != NULL) { 0403 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending device pin request failed", err); 0404 return; 0405 } 0406 0407 state_change_emit(harmony, MP3TUNES_HARMONY_STATE_WAITING_FOR_PIN); 0408 } 0409 0410 LmHandlerResult harmony_get_device_email_callback(LmMessageHandler* handler, LmConnection *connection, LmMessage *message, gpointer void_harmony) { 0411 char *email; 0412 MP3tunesHarmony *harmony = MP3TUNES_HARMONY(void_harmony); 0413 LmMessageNode *harmony_email_node; 0414 0415 (void)handler; 0416 (void)connection; 0417 0418 harmony_email_node = lm_message_node_get_child(message->node, "email"); 0419 if (harmony_email_node) { 0420 email = g_strdup(lm_message_node_get_value(harmony_email_node)); 0421 sleep(2); /* 0422 FIXME: This exists because mp3tunes website logins cannot 0423 exceed 1 per second. When a device connects that has been 0424 fully authenticated previously it will rapidly reconnect 0425 three times as it grabs pin, then email, then connects completely. 0426 */ 0427 mp3tunes_harmony_set_email(harmony, email); 0428 g_free(email); 0429 close_connection(harmony); 0430 open_connection(harmony); 0431 return LM_HANDLER_RESULT_REMOVE_MESSAGE; 0432 } 0433 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; 0434 } 0435 0436 void harmony_get_device_email(MP3tunesHarmony *harmony) { 0437 LmMessage *message_out; 0438 LmMessageHandler *handler; 0439 LmMessageNode *message_out_node; 0440 GError *err = NULL; 0441 handler = lm_message_handler_new(harmony_get_device_email_callback, (gpointer)harmony, NULL); 0442 0443 message_out = lm_message_new(MP3TUNES_HARMONY_CONDUCTOR, LM_MESSAGE_TYPE_IQ); 0444 message_out_node = lm_message_node_add_child(message_out->node, "email", NULL); 0445 lm_message_node_set_attribute(message_out_node, "xmlns", MP3TUNES_HARMONY_XMLNS); 0446 0447 lm_connection_send_with_reply(harmony->connection, 0448 message_out, 0449 handler, 0450 &err); 0451 lm_message_unref(message_out); 0452 if (err != NULL) { 0453 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending device email request failed", err); 0454 return; 0455 } 0456 0457 state_change_emit(harmony, MP3TUNES_HARMONY_STATE_WAITING_FOR_EMAIL); 0458 } 0459 0460 void authenticate_known_callback(LmConnection* connection, gboolean success, gpointer void_harmony) { 0461 GError *err = NULL; 0462 MP3tunesHarmony *harmony = MP3TUNES_HARMONY(void_harmony); 0463 (void)connection; 0464 if (success) { 0465 harmony->connected = TRUE; 0466 state_change_emit(harmony, MP3TUNES_HARMONY_STATE_CONNECTED); 0467 mp3tunes_harmony_send_device_status(harmony, &err); 0468 if (err) { 0469 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending device status failed", err); 0470 } 0471 } else { 0472 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Authentication failed", NULL); 0473 close_connection(harmony); 0474 } 0475 } 0476 0477 void authenticate_new_callback(LmConnection* connection, gboolean success, gpointer void_harmony) { 0478 MP3tunesHarmony *harmony = MP3TUNES_HARMONY(void_harmony); 0479 (void)connection; 0480 if (success) { 0481 harmony_get_device_pin(harmony); 0482 } else { 0483 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Authentication failed", NULL); 0484 close_connection(harmony); 0485 } 0486 } 0487 0488 void authenticate_unknown_callback(LmConnection* connection, gboolean success, gpointer void_harmony) { 0489 MP3tunesHarmony *harmony = MP3TUNES_HARMONY(void_harmony); 0490 (void)connection; 0491 if (success) { 0492 harmony_get_device_email(harmony); 0493 } else { 0494 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Authentication failed", NULL); 0495 close_connection(harmony); 0496 } 0497 } 0498 0499 void open_connection_callback(LmConnection* connection, gboolean success, gpointer void_harmony) { 0500 GError *err = NULL; 0501 MP3tunesHarmony* harmony = MP3TUNES_HARMONY(void_harmony); 0502 LmMessage *message; 0503 0504 if (!success) { 0505 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Failed to open connection", err); 0506 return; 0507 } 0508 0509 message = lm_message_new_with_sub_type(NULL, 0510 LM_MESSAGE_TYPE_PRESENCE, 0511 LM_MESSAGE_SUB_TYPE_AVAILABLE); 0512 lm_connection_send(connection, message, &err); 0513 lm_message_unref(message); 0514 if (err != NULL) { 0515 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending presence message failed", err); 0516 return; 0517 } 0518 0519 /* Authenticate, known */ 0520 if (harmony->device_email != NULL && harmony->device_pin != NULL) { 0521 if (!lm_connection_authenticate(connection, 0522 harmony->device_formatted_email, 0523 g_strdup_printf("PIN-%s", harmony->device_pin), 0524 harmony->device_pin, 0525 (LmResultFunction) authenticate_known_callback, 0526 harmony, 0527 NULL, 0528 &err)) { 0529 if (err != NULL) { 0530 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending authentication failed", err); 0531 } 0532 return; 0533 } 0534 return; 0535 } 0536 0537 /* Authenticate, unknown */ 0538 if (harmony->device_identifier != NULL && 0539 harmony->device_pin != NULL && 0540 strncmp(harmony->device_pin, "NULL", 4) != 0) { 0541 if (!lm_connection_authenticate(connection, 0542 harmony->device_identifier, 0543 MP3TUNES_HARMONY_DEFAULT_PASSWORD, 0544 harmony->device_pin, 0545 (LmResultFunction) authenticate_unknown_callback, 0546 harmony, 0547 NULL, 0548 &err)) { 0549 if (err != NULL) { 0550 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending authentication failed", err); 0551 } 0552 return; 0553 } 0554 return; 0555 } 0556 0557 /* Authenticate, new */ 0558 if (harmony->device_identifier != NULL) { 0559 if (!lm_connection_authenticate(connection, 0560 harmony->device_identifier, 0561 MP3TUNES_HARMONY_DEFAULT_PASSWORD, 0562 harmony->device_pin, 0563 (LmResultFunction) authenticate_new_callback, 0564 harmony, 0565 NULL, 0566 &err)) { 0567 if (err != NULL) { 0568 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Sending authentication failed", err); 0569 } 0570 return; 0571 } 0572 return; 0573 } 0574 0575 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "A device identifier is required to authenticate", NULL); 0576 return; 0577 } 0578 0579 void rebuild_connection(MP3tunesHarmony* harmony) { 0580 gchar* jid; 0581 0582 /* 0583 if (harmony->connection != NULL) { 0584 lm_connection_unref(harmony->connection); 0585 harmony->connection = NULL; 0586 } 0587 if (harmony->harmony_download_message_handler != NULL) { 0588 lm_message_handler_unref(harmony->harmony_download_message_handler); 0589 harmony->harmony_download_message_handler = NULL; 0590 } 0591 */ 0592 harmony->connection = lm_connection_new(harmony->host); 0593 harmony->harmony_iq_message_handler = lm_message_handler_new(harmony_iq_callback, harmony, NULL); 0594 0595 lm_connection_set_port(harmony->connection, harmony->port); 0596 0597 jid = mp3tunes_harmony_get_jid(harmony); 0598 g_debug("Logging in with: %s", jid); 0599 lm_connection_set_jid(harmony->connection, jid); 0600 g_free(jid); 0601 lm_connection_register_message_handler(harmony->connection, harmony->harmony_iq_message_handler, LM_MESSAGE_TYPE_IQ, LM_HANDLER_PRIORITY_LAST); 0602 } 0603 0604 gboolean open_connection(MP3tunesHarmony *harmony) { 0605 GError *err = NULL; 0606 0607 rebuild_connection(harmony); 0608 0609 if (!lm_connection_is_open(harmony->connection)) { 0610 lm_connection_open(harmony->connection, 0611 (LmResultFunction) open_connection_callback, 0612 harmony, 0613 NULL, 0614 &err); 0615 0616 if (err != NULL) { 0617 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Opening the connection failed", err); 0618 return FALSE; 0619 } 0620 } 0621 0622 return TRUE; 0623 } 0624 0625 gboolean close_connection(MP3tunesHarmony *harmony) { 0626 GError *err = NULL; 0627 0628 if (lm_connection_is_open(harmony->connection)) { 0629 lm_connection_close(harmony->connection, &err); 0630 lm_connection_unref(harmony->connection); 0631 if (err != NULL) { 0632 error_emit(harmony, MP3TUNES_HARMONY_ERROR_MISC, "Closing the connection failed", err); 0633 return FALSE; 0634 } 0635 /* return TRUE; */ 0636 /* state_change_emit(harmony, MP3TUNES_HARMONY_STATE_DISCONNECTED); */ 0637 } 0638 0639 return TRUE; 0640 } 0641 0642 gboolean mp3tunes_harmony_disconnect(MP3tunesHarmony *harmony, GError** err) { 0643 gboolean success = close_connection(harmony); 0644 harmony->connected = FALSE; 0645 if (success == FALSE) { 0646 *err = harmony->error; 0647 return success; 0648 } 0649 return success; 0650 } 0651 0652 gboolean mp3tunes_harmony_connect(MP3tunesHarmony* harmony, GError** err) { 0653 gboolean success = FALSE; 0654 if (harmony->connected) { 0655 return TRUE; 0656 } 0657 0658 success = open_connection(harmony); 0659 0660 if (success == FALSE) { 0661 *err = harmony->error; 0662 mp3tunes_harmony_disconnect(harmony, err); 0663 return success; 0664 } 0665 return success; 0666 } 0667 0668 void mp3tunes_harmony_send_device_status(MP3tunesHarmony *harmony, GError **err) { 0669 LmMessage *message_out; 0670 /*LmMessageHandler *handler;*/ 0671 LmMessageNode* status_message; 0672 0673 GList *current = NULL; 0674 mp3tunes_harmony_device_attribute_t *da; 0675 0676 char* name = NULL; 0677 char* value = NULL; 0678 0679 /*handler = lm_message_handler_new(harmony_get_device_email_callback, (gpointer)harmony, NULL);*/ 0680 0681 message_out = lm_message_new_with_sub_type(MP3TUNES_HARMONY_CONDUCTOR, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET); 0682 status_message = lm_message_node_add_child(message_out->node, "deviceStatus", NULL); 0683 lm_message_node_set_attribute(status_message, "xmlns", MP3TUNES_HARMONY_XMLNS); 0684 0685 current = g_list_first(harmony->device_attributes); 0686 while (current != NULL) { 0687 da = (mp3tunes_harmony_device_attribute_t*) current->data; 0688 name = da->attribute_name; 0689 if (da->attribute_value_type == MP3TUNES_HARMONY_DEVICE_ATTRIBUTE_TYPE_STRING) { 0690 value = g_strdup(da->attribute_string_value); 0691 } else if (da->attribute_value_type == MP3TUNES_HARMONY_DEVICE_ATTRIBUTE_TYPE_INT) { 0692 value = g_strdup_printf("%lld", da->attribute_int_value); 0693 } 0694 lm_message_node_set_attribute(status_message, name, value); 0695 g_free(value); 0696 current = g_list_next(current); 0697 } 0698 0699 lm_connection_send(harmony->connection, message_out, err); 0700 lm_message_unref(message_out); 0701 if (err != NULL) { 0702 return; 0703 } 0704 } 0705 0706 void mp3tunes_harmony_set_identifier(MP3tunesHarmony *harmony, char *identifier) { 0707 if (harmony->device_identifier != NULL) { 0708 free(harmony->device_identifier); 0709 } 0710 harmony->device_identifier = g_strdup(identifier); 0711 } 0712 0713 void mp3tunes_harmony_set_pin(MP3tunesHarmony *harmony, const char *pin) { 0714 if (harmony->device_pin != NULL) { 0715 free(harmony->device_pin); 0716 } 0717 harmony->device_pin = g_strdup(pin); 0718 } 0719 0720 void mp3tunes_harmony_set_email(MP3tunesHarmony *harmony, char *email) { 0721 if (harmony->device_email != NULL) { 0722 free(harmony->device_email); 0723 free(harmony->device_formatted_email); 0724 } 0725 harmony->device_email = g_strdup(email); 0726 harmony->device_formatted_email = g_strdup(email); 0727 harmony_format_email(&harmony->device_formatted_email); 0728 } 0729 0730 void mp3tunes_harmony_set_device_attribute(MP3tunesHarmony *harmony, const char *attribute, ...) { 0731 va_list argp; 0732 mp3tunes_harmony_device_attribute_t* da; 0733 0734 GList *current = NULL; 0735 mp3tunes_harmony_device_attribute_t *current_da; 0736 0737 da = (mp3tunes_harmony_device_attribute_t*)malloc(sizeof(mp3tunes_harmony_device_attribute_t)); 0738 if (da == NULL) 0739 return; 0740 0741 va_start(argp, attribute); 0742 0743 if (strcmp(attribute, "device-description") == 0) { 0744 da->attribute_name = g_strdup("deviceDescription"); 0745 da->attribute_string_value = g_strdup(va_arg(argp, char *)); 0746 da->attribute_value_type = MP3TUNES_HARMONY_DEVICE_ATTRIBUTE_TYPE_STRING; 0747 } else if (strcmp(attribute, "total-bytes") == 0) { 0748 da->attribute_name = g_strdup("total-bytes"); 0749 da->attribute_int_value = va_arg(argp, long long int); 0750 da->attribute_value_type = MP3TUNES_HARMONY_DEVICE_ATTRIBUTE_TYPE_INT; 0751 } else if (strcmp(attribute, "available-bytes") == 0) { 0752 da->attribute_name = g_strdup("available-bytes"); 0753 da->attribute_int_value = va_arg(argp, long long int); 0754 da->attribute_value_type = MP3TUNES_HARMONY_DEVICE_ATTRIBUTE_TYPE_INT; 0755 } else { 0756 va_end(argp); 0757 free(da); 0758 return; 0759 } 0760 0761 current = g_list_first(harmony->device_attributes); 0762 while (current != NULL) { 0763 current_da = (mp3tunes_harmony_device_attribute_t*) current->data; 0764 if (strcmp((current_da->attribute_name), da->attribute_name) == 0) { 0765 harmony->device_attributes = g_list_insert_before(harmony->device_attributes, current, da); 0766 harmony->device_attributes = g_list_remove(harmony->device_attributes, current_da); 0767 va_end(argp); 0768 return; 0769 } 0770 current = g_list_next(current); 0771 } 0772 0773 harmony->device_attributes = g_list_prepend(harmony->device_attributes, da); 0774 va_end(argp); 0775 return; 0776 } 0777 0778 char *mp3tunes_harmony_get_identifier(MP3tunesHarmony *harmony) { 0779 return harmony->device_identifier; 0780 } 0781 0782 char *mp3tunes_harmony_get_pin(MP3tunesHarmony *harmony) { 0783 return harmony->device_pin; 0784 } 0785 0786 char *mp3tunes_harmony_get_email(MP3tunesHarmony *harmony) { 0787 return harmony->device_email; 0788 } 0789 0790 char *mp3tunes_harmony_get_jid(MP3tunesHarmony *harmony) { 0791 if (harmony->device_formatted_email != NULL && harmony->device_pin != NULL) { 0792 return g_strdup_printf("%s@%s/%s", harmony->device_formatted_email, MP3TUNES_HARMONY_JID_HOST, harmony->device_pin); 0793 } 0794 if (harmony->device_identifier != NULL && 0795 harmony->device_pin != NULL && 0796 strncmp(harmony->device_pin, "NULL", 4) != 0) { 0797 return g_strdup_printf("%s@%s/%s", harmony->device_identifier, MP3TUNES_HARMONY_JID_HOST, harmony->device_pin); 0798 } 0799 if (harmony->device_identifier != NULL) { 0800 return g_strdup_printf("%s@%s/%s", harmony->device_identifier, MP3TUNES_HARMONY_JID_HOST, harmony->device_pin); 0801 } 0802 return NULL; 0803 } 0804 0805 MP3tunesHarmony *mp3tunes_harmony_new(void) { 0806 return MP3TUNES_HARMONY(g_object_new(MP3TUNES_TYPE_HARMONY, NULL)); 0807 } 0808 0809 static void mp3tunes_harmony_class_init(MP3tunesHarmonyClass *klass) { 0810 klass->state_change_signal_id = g_signal_new("state_change", 0811 G_TYPE_FROM_CLASS(klass), 0812 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0813 0, 0814 NULL, 0815 NULL, 0816 g_cclosure_marshal_VOID__UINT, 0817 G_TYPE_NONE, 0818 1, 0819 G_TYPE_UINT); 0820 0821 klass->error_signal_id = g_signal_new("error", 0822 G_TYPE_FROM_CLASS(klass), 0823 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0824 0, 0825 NULL, 0826 NULL, 0827 g_cclosure_marshal_VOID__VOID, 0828 G_TYPE_NONE, 0829 0); 0830 0831 klass->download_pending_signal_id = g_signal_new("download_pending", 0832 G_TYPE_FROM_CLASS(klass), 0833 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0834 0, 0835 NULL, 0836 NULL, 0837 g_cclosure_marshal_VOID__POINTER, 0838 G_TYPE_NONE, 0839 1, 0840 G_TYPE_POINTER); 0841 0842 klass->download_ready_signal_id = g_signal_new("download_ready", 0843 G_TYPE_FROM_CLASS(klass), 0844 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0845 0, 0846 NULL, 0847 NULL, 0848 g_cclosure_marshal_VOID__POINTER, 0849 G_TYPE_NONE, 0850 1, 0851 G_TYPE_POINTER); 0852 } 0853 0854 static void mp3tunes_harmony_init(MP3tunesHarmony *self) { 0855 char *port; 0856 self->connected = FALSE; 0857 0858 mp3tunes_locker_init(&self->mp3tunes_locker, "7794175043"); 0859 0860 self->download_queue = g_queue_new(); 0861 0862 self->sid_state = MP3TUNES_HARMONY_SID_STATE_NONE; 0863 0864 self->error = NULL; 0865 0866 self->device_identifier = NULL; 0867 self->device_pin = NULL; 0868 mp3tunes_harmony_set_pin(self, "NULL"); 0869 self->device_email = NULL; 0870 0871 self->device_attributes = NULL; 0872 0873 self->host = getenv("MP3TUNES_HARMONY_HOST"); 0874 if(self->host == NULL) { 0875 self->host = MP3TUNES_HARMONY_HOST; 0876 } 0877 0878 port = getenv("MP3TUNES_HARMONY_PORT"); 0879 if(port == NULL) { 0880 self->port = MP3TUNES_HARMONY_PORT; 0881 } else { 0882 self->port = atoi(port); 0883 free(port); 0884 } 0885 0886 self->connection = NULL; 0887 self->harmony_iq_message_handler = NULL; 0888 }