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 }