#include "mrklib_priv.h" struct _Mrk { const char *host; int port; Ecore_Ipc_Server *server; Eina_List *handlers; FILE *f; const char *file; Eina_Bool query; struct { void (*connect) (void *data, Mrk *server); void (*disconnect) (void *data, Mrk *server); void (*upload_begin) (void *data, Mrk *server); void (*upload_progress) (void *data, Mrk *server, double pos); void (*upload_end) (void *data, Mrk *server); void (*upload_success) (void *data, Mrk *server, Eina_Bool sucess); void (*download_begin) (void *data, Mrk *server); void (*download_progress) (void *data, Mrk *server, double pos); void (*download_end) (void *data, Mrk *server); void (*download_success) (void *data, Mrk *server, const char *file); void (*answer_begin) (void *data, Mrk *server); void (*answer_progress) (void *data, Mrk *server, const char *result); void (*answer_end) (void *data, Mrk *server); void (*getkey) (void *data, Mrk *server, const char *result); } func; struct { void *connect; void *disconnect; void *upload_begin; void *upload_progress; void *upload_end; void *upload_success; void *download_begin; void *download_progress; void *download_end; void *download_success; void *answer_begin; void *answer_progress; void *answer_end; void *getkey; } data; }; static void _mrk_identify(Mrk *server) { char tmp[PATH_MAX]; // send client uuid - should be unique per client just to tell one // apart from another - nothing more ecore_ipc_server_send(server->server, M_OP, M_ID_UUID, 0, 0, 0, _mrk_uuid, _mrk_uuid_len); // send arch string - determined by compile time macros snprintf(tmp, sizeof(tmp), "%s-%s", OS, ARCH); ecore_ipc_server_send(server->server, M_OP, M_ID_ARCH, 0, 0, 0, tmp, strlen(tmp)); // send efl version - this is used by the server to filter results // that are only relevent to you snprintf(tmp, sizeof(tmp), "%i.%i.%i", eina_version->major, eina_version->minor, eina_version->micro); ecore_ipc_server_send(server->server, M_OP, M_ID_VERSION, 0, 0, 0, tmp, strlen(tmp)); } static Eina_Bool _mrk_upload(Mrk *server, const char *file) { FILE *f; char buf[10000]; size_t size; const char *fname; if ((server->f) || (server->query)) return EINA_FALSE; // XXX: adjust protocol so we get ack's for each buf f = fopen(file, "rb"); if (!f) return EINA_FALSE; server->f = f; fname = ecore_file_file_get(file); if (!fname) goto done; ecore_ipc_server_send(server->server, M_OP, M_UP_START, 0, 0, 0, fname, strlen(fname)); if (server->func.upload_begin) server->func.upload_begin(server->data.upload_begin, server); for (;;) { size = fread(buf, 1, 10000, f); if (size > 0) { ecore_ipc_server_send(server->server, 10, M_UP_DATA, 0, 0, 0, buf, size); // XXX: calculate position 0.0 -> 1.0 if (server->func.upload_progress) server->func.upload_progress(server->data.upload_progress, server, 0.5); } else break; } ecore_ipc_server_send(server->server, M_OP, M_UP_END, 0, 0, 0, NULL, 0); if (server->func.upload_end) server->func.upload_end(server->data.upload_end, server); done: return EINA_TRUE; } static Eina_Bool _mrk_upload_data(Mrk *server, Ecore_Ipc_Event_Server_Data *e) { if (e->minor == M_UP_OK) { if (server->f) fclose(server->f); server->f = NULL; if (server->func.upload_success) server->func.upload_success(server->data.upload_success, server, EINA_TRUE); return EINA_TRUE; } else if (e->minor == M_UP_FAIL) { if (server->f) fclose(server->f); server->f = NULL; // XXX: e->data should contain some failure string/info if (server->func.upload_success) server->func.upload_success(server->data.upload_success, server, EINA_FALSE); return EINA_TRUE; } // XXX: we should have some other status - eg unpack src worked, // src sanity check passed, some build failed when/where or succeeded // etc. etc. return EINA_FALSE; } static Eina_Bool _mrk_download(Mrk *server, const char *package) { if ((server->f) || (server->query)) return EINA_FALSE; ecore_ipc_server_send(server->server, M_OP, M_QRY_GET, 0, 0, 0, package, strlen(package)); return EINA_TRUE; } static Eina_Bool _mrk_download_data(Mrk *server, Ecore_Ipc_Event_Server_Data *e) { char *file = NULL; if ((e->minor == M_DOWN_START) || (e->minor == M_SRC_START)) { if ((e->size > 0) && (e->size <= 1000) && (e->data)) { char *file = _mrk_util_proto_string(e); if (file) { if (_mrk_util_plain_file_check(file)) { FILE *f; char tmp[PATH_MAX]; snprintf(tmp, sizeof(tmp), "%s/%s", _mrk_appdir_tmp, file); f = fopen(tmp, "wb"); if (!f) goto fail; server->f = f; server->file = eina_stringshare_add(tmp); if (server->func.download_begin) server->func.download_begin(server->data.download_begin, server); } else goto fail; } else goto fail; } else { fail: if (server->func.download_success) server->func.download_success(server->data.download_success, server, NULL); } free(file); return EINA_TRUE; } else if ((e->minor == M_DOWN_DATA) || (e->minor == M_SRC_DATA)) { double pos = 0.5; if (e->ref_to > 0) pos = (double)e->ref / (double)e->ref_to; if ((server->f) && (e->data) && (e->size > 0) && (e->size <= 10000)) { fwrite(e->data, e->size, 1, server->f); if (server->func.download_progress) server->func.download_progress(server->data.download_progress, server, pos); } return EINA_TRUE; } else if ((e->minor == M_DOWN_END) || (e->minor == M_SRC_END)) { const char *file = server->file; server->file = NULL; if (server->f) fclose(server->f); server->f = NULL; if (server->func.download_end) server->func.download_end(server->data.download_end, server); // XXX: check signature so we can verify dl is not broken and it's // from a proper pkg server (signed by pkg server priv key, check // with pub key if (server->func.download_success) server->func.download_success(server->data.download_success, server, file); eina_stringshare_del(file); return EINA_TRUE; } return EINA_FALSE; } static Eina_Bool _mrk_download_src(Mrk *server, const char *package) { if ((server->f) || (server->query)) return EINA_FALSE; ecore_ipc_server_send(server->server, M_OP, M_QRY_GETSRC, 0, 0, 0, package, strlen(package)); return EINA_TRUE; } static Eina_Bool _mrk_download_src_data(Mrk *server, Ecore_Ipc_Event_Server_Data *e) { return _mrk_download_data(server, e); } static Eina_Bool _mrk_query_list(Mrk *server, const char *category) { if ((server->f) || (server->query)) return EINA_FALSE; ecore_ipc_server_send(server->server, M_OP, M_QRY_LIST, 0, 0, 0, category, category ? strlen(category) : 0); return EINA_TRUE; } static Eina_Bool _mrk_query_search(Mrk *server, const char *keywords) { if ((server->f) || (server->query)) return EINA_FALSE; if (!keywords) return EINA_FALSE; ecore_ipc_server_send(server->server, M_OP, M_QRY_SEARCH, 0, 0, 0, keywords, strlen(keywords)); return EINA_TRUE; } static Eina_Bool _mrk_query_data(Mrk *server, Ecore_Ipc_Event_Server_Data *e) { if (e->minor == M_ANS_START) { if (server->func.answer_begin) server->func.answer_begin(server->data.answer_begin, server); return EINA_TRUE; } else if (e->minor == M_ANS_DATA) { if ((e->data) && (e->size > 0) && (e->size <= 10000)) { char *str = _mrk_util_proto_string(e); if (str) { if (server->func.answer_progress) server->func.answer_progress(server->data.answer_progress, server, str); free(str); } } return EINA_TRUE; } else if (e->minor == M_ANS_END) { server->query = EINA_FALSE; if (server->func.answer_end) server->func.answer_end(server->data.answer_end, server); return EINA_TRUE; } return EINA_FALSE; } static Eina_Bool _mrk_getkey(Mrk *server) { if (server->f) return EINA_FALSE; ecore_ipc_server_send(server->server, M_OP, M_GETKEY_REQ, 0, 0, 0, NULL, 0); return EINA_TRUE; } static Eina_Bool _mrk_getkey_data(Mrk *server, Ecore_Ipc_Event_Server_Data *e) { if (e->minor == M_GETKEY_ANS) { if ((e->data) && (e->size > 0) && (e->size <= 100000)) { char *str = _mrk_util_proto_string(e); if (str) { if (server->func.getkey) server->func.getkey(server->data.getkey, server, str); free(str); } } return EINA_TRUE; } return EINA_FALSE; } static Eina_Bool _mrk_data_handle(Mrk *server, Ecore_Ipc_Event_Server_Data *e) { if ((e->minor > M_UP_B) && (e->minor < M_UP_E)) return _mrk_upload_data(server, e); else if ((e->minor > M_DOWN_B) && (e->minor < M_DOWN_E)) return _mrk_download_data(server, e); else if ((e->minor > M_SRC_B) && (e->minor < M_SRC_E)) return _mrk_download_src_data(server, e); else if ((e->minor > M_ANS_B) && (e->minor < M_ANS_E)) return _mrk_query_data(server, e); else if ((e->minor > M_GETKEY_B) && (e->minor < M_GETKEY_E)) return _mrk_getkey_data(server, e); return EINA_FALSE; } static Eina_Bool _mrk_cb_add(void *data, int type EINA_UNUSED, void *event) { Ecore_Ipc_Event_Server_Add *e = event; Mrk *server = data; if (server->server != e->server) return EINA_TRUE; if (server->func.connect) server->func.connect(server->data.connect, server); return EINA_FALSE; } static Eina_Bool _mrk_cb_del(void *data, int type EINA_UNUSED, void *event) { Ecore_Ipc_Event_Server_Del *e = event; Mrk *server = data; if (server->server != e->server) return EINA_TRUE; if (server->func.disconnect) server->func.disconnect(server->data.disconnect, server); return EINA_FALSE; } static Eina_Bool _mrk_cb_data(void *data, int type EINA_UNUSED, void *event) { Ecore_Ipc_Event_Server_Data *e = event; Mrk *server = data; if (server->server != e->server) return EINA_TRUE; if (e->major != M_OP) return EINA_TRUE; if (!_mrk_data_handle(server, e)) return EINA_TRUE; return EINA_FALSE; } EAPI Mrk * mrk_connect(const char *host, int port) { Mrk *server; if (!host) host = _mrk_server_host; if (port <= 0) port = _mrk_server_port; server = calloc(1, sizeof(Mrk)); if (!server) return NULL; server->host = eina_stringshare_add(host); server->port = port; server->handlers = eina_list_append(server->handlers, ecore_event_handler_add (ECORE_IPC_EVENT_SERVER_ADD, _mrk_cb_add, server)); server->handlers = eina_list_append(server->handlers, ecore_event_handler_add (ECORE_IPC_EVENT_SERVER_DEL, _mrk_cb_del, server)); server->handlers = eina_list_append(server->handlers, ecore_event_handler_add (ECORE_IPC_EVENT_SERVER_DATA, _mrk_cb_data, server)); server->server = ecore_ipc_server_connect(ECORE_IPC_REMOTE_SYSTEM, (char *)server->host, server->port, server); _mrk_identify(server); return server; } EAPI void mrk_disconnect(Mrk *server) { Ecore_Event_Handler *hnd; if (!server) return; ecore_ipc_server_del(server->server); EINA_LIST_FREE(server->handlers, hnd) ecore_event_handler_del(hnd); eina_stringshare_del(server->host); if (server->f) { fclose(server->f); if (server->file) ecore_file_unlink(server->file); } eina_stringshare_del(server->file); free(server); } EAPI Eina_Bool mrk_upload(Mrk *server, const char *file) { return _mrk_upload(server, file); } EAPI Eina_Bool mrk_download(Mrk *server, const char *package) { return _mrk_download(server, package); } EAPI Eina_Bool mrk_download_source(Mrk *server, const char *package) { return _mrk_download_src(server, package); } EAPI Eina_Bool mrk_list(Mrk *server, const char *category) { return _mrk_query_list(server, category); } EAPI Eina_Bool mrk_search(Mrk *server, const char *keys) { return _mrk_query_search(server, keys); } EAPI Eina_Bool mrk_getkey(Mrk *server) { return _mrk_getkey(server); } EAPI void mrk_callback_connect_set(Mrk *server, void (*connect) (void *data, Mrk *server), void *connect_data, void (*disconnect) (void *data, Mrk *server), void *disconnect_data) { server->func.connect = connect; server->data.connect = connect_data; server->func.disconnect = disconnect; server->data.disconnect = disconnect_data; } EAPI void mrk_callback_upload_set(Mrk *server, void (*upload_begin) (void *data, Mrk *server), void *upload_begin_data, void (*upload_progress) (void *data, Mrk *server, double pos), void *upload_progress_data, void (*upload_end) (void *data, Mrk *server), void *upload_end_data, void (*upload_success) (void *data, Mrk *server, Eina_Bool sucess), void *upload_success_data) { server->func.upload_begin = upload_begin; server->data.upload_begin = upload_begin_data; server->func.upload_progress = upload_progress; server->data.upload_progress = upload_progress_data; server->func.upload_end = upload_end; server->data.upload_end = upload_end_data; server->func.upload_success = upload_success; server->data.upload_success = upload_success_data; } EAPI void mrk_callback_download_set(Mrk *server, void (*download_begin) (void *data, Mrk *server), void *download_begin_data, void (*download_progress) (void *data, Mrk *server, double pos), void *download_progress_data, void (*download_end) (void *data, Mrk *server), void *download_end_data, void (*download_success) (void *data, Mrk *server, const char *file), void *download_success_data) { server->func.download_begin = download_begin; server->data.download_begin = download_begin_data; server->func.download_progress = download_progress; server->data.download_progress = download_progress_data; server->func.download_end = download_end; server->data.download_end = download_end_data; server->func.download_success = download_success; server->data.download_success = download_success_data; } EAPI void mrk_callback_answer_set(Mrk *server, void (*answer_begin) (void *data, Mrk *server), void *answer_begin_data, void (*answer_progress) (void *data, Mrk *server, const char *result), void *answer_progress_data, void (*answer_end) (void *data, Mrk *server), void *answer_end_data) { server->func.answer_begin = answer_begin; server->data.answer_begin = answer_begin_data; server->func.answer_progress = answer_progress; server->data.answer_progress = answer_progress_data; server->func.answer_end = answer_end; server->data.answer_end = answer_end_data; } EAPI void mrk_callback_getkey_set(Mrk *server, void (*getkey) (void *data, Mrk *server, const char *keydata), void *getkey_data) { server->func.getkey = getkey; server->data.getkey = getkey_data; }