Eina_Bool email_pop3_stat_read(Email *e, const unsigned char *recv, size_t size) { Email_Stat_Cb cb; int num; size_t len; cb = eina_list_data_get(e->cbs); if ((!email_op_ok((const unsigned char *)recv, size)) || (sscanf((char*)recv, "+OK %u %zu", &num, &len) != 2)) { ERR("Error with STAT"); if (cb) cb(e, 0, 0); return EINA_TRUE; } INF("STAT returned %u messages (%zu octets)", num, len); if (cb) cb(e, num, len); return EINA_TRUE; }
Eina_Bool email_pop3_list_read(Email *e, Ecore_Con_Event_Server_Data *ev) { Email_List_Cb cb; Eina_List *list = NULL; Email_List_Item *it; const char *p, *n; const unsigned char *data; size_t size; if ((!e->buf) && (!email_op_ok(ev->data, ev->size))) { ERR("Error with LIST"); cb = eina_list_data_get(e->cbs); if (cb) cb(e, NULL); return EINA_TRUE; } if (e->buf) { eina_binbuf_append_length(e->buf, ev->data, ev->size); data = eina_binbuf_string_get(e->buf); size = eina_binbuf_length_get(e->buf); } else { data = ev->data; size = ev->size; } for (n = (char*)memchr(data + 3, '\n', size - 3), size -= (n - (char*)data); n && (size > 1); p = n, n = (char*)memchr(n, '\n', size - 1), size -= (n - (char*)data)) { it = calloc(1, sizeof(Email_List_Item)); if (sscanf(++n, "%u %zu", &it->id, &it->size) != 2) { free(it); break; } INF("Message %u: %zu octets", it->id, it->size); list = eina_list_append(list, it); } if (n[0] == '.') { cb = eina_list_data_get(e->cbs); INF("LIST returned %u messages", eina_list_count(list)); if (cb) cb(e, list); EINA_LIST_FREE(list, it) free(it); if (e->buf) { eina_binbuf_free(e->buf); e->buf = NULL; } } else if (!e->buf) { e->buf = eina_binbuf_new(); eina_binbuf_append_length(e->buf, (const unsigned char*)(n), size - (n - (char*)data)); } return EINA_TRUE; }
Eina_Bool email_pop3_list_read(Email *e, Ecore_Con_Event_Server_Data *ev) { Email_List_Cb cb; Eina_List *next, *list = NULL; Email_List_Item *it; const char *n; unsigned char *data; int len; size_t size; if ((!e->buf) && (!email_op_ok(ev->data, ev->size))) { ERR("Error with LIST"); cb = e->cbs->data; e->cbs = eina_list_remove_list(e->cbs, e->cbs); if (cb) cb(e, NULL); return EINA_TRUE; } next = e->ev ? e->ev : list; if (e->buf) { eina_binbuf_append_length(e->buf, ev->data, ev->size); data = (unsigned char*)eina_binbuf_string_get(e->buf); len = eina_binbuf_length_get(e->buf); } else { data = ev->data; len = ev->size; } for (n = (char*)memchr(data + 3, '\n', len - 3), size = len - (n - (char*)data); n && (size > 1); n = (char*)memchr(n, '\n', size - 1), size = len - (n - (char*)data)) { it = calloc(1, sizeof(Email_List_Item)); if (sscanf(++n, "%u %zu", &it->id, &it->size) != 2) { free(it); break; } INF("Message %u: %zu octets", it->id, it->size); list = eina_list_append(list, it); } if (!memcmp(n - 2, "\r\n.\r\n", 5)) { cb = e->cbs->data; e->cbs = eina_list_remove_list(e->cbs, e->cbs); INF("LIST returned %u messages", eina_list_count(list)); if (cb) cb(e, list); EINA_LIST_FREE(list, it) free(it); if (e->buf) { eina_binbuf_free(e->buf); e->buf = NULL; } return EINA_TRUE; } else if (!e->buf) { e->buf = eina_binbuf_new(); eina_binbuf_append_length(e->buf, (unsigned char*)n, ev->size - (n - (char*)ev->data)); } return EINA_FALSE; }
void email_login_pop(Email *e, Ecore_Con_Event_Server_Data *ev) { char *buf; size_t size; switch (e->state) { case EMAIL_STATE_SSL: if (!email_op_ok(ev->data, ev->size)) { ERR("Could not create secure connection!"); ecore_con_server_del(ev->server); return; } ecore_con_ssl_server_upgrade(e->svr, ECORE_CON_USE_MIXED); ecore_con_ssl_server_verify_basic(e->svr); e->flags = ECORE_CON_USE_MIXED; return; case EMAIL_STATE_INIT: if (!email_op_ok(ev->data, ev->size)) { ERR("Not a POP3 server!"); ecore_con_server_del(ev->server); return; } if (ev->size > 20) { const unsigned char *end; end = memrchr(ev->data + 3, '>', ev->size - 3); if (end) { const unsigned char *start; start = memrchr(ev->data + 3, '<', end - (unsigned char*)ev->data); if (start) { e->features.pop_features.apop = EINA_TRUE; e->features.pop_features.apop_str = eina_binbuf_new(); eina_binbuf_append_length(e->features.pop_features.apop_str, start, end - start + 1); } } } if (e->secure && (!e->flags)) { email_write(e, "STLS\r\n", sizeof("STLS\r\n") - 1); e->state++; return; } e->state = EMAIL_STATE_USER; ev = NULL; case EMAIL_STATE_USER: if (!ev) { unsigned char digest[16]; char md5buf[33]; if (!e->features.pop_features.apop) { INF("Beginning AUTH PLAIN"); size = sizeof(char) * (sizeof("USER ") - 1 + sizeof("\r\n") - 1 + strlen(e->username)) + 1; buf = alloca(size); snprintf(buf, size, "USER %s\r\n", e->username); email_write(e, buf, size - 1); return; } INF("Beginning AUTH APOP"); e->state++; eina_binbuf_append_length(e->features.pop_features.apop_str, (unsigned char*)e->password, strlen(e->password)); md5_buffer((char*)eina_binbuf_string_get(e->features.pop_features.apop_str), eina_binbuf_length_get(e->features.pop_features.apop_str), digest); email_md5_digest_to_str(digest, md5buf); size = sizeof(char) * (sizeof("APOP ") - 1 + sizeof("\r\n") - 1 + strlen(e->username)) + sizeof(md5buf); buf = alloca(size); snprintf(buf, size, "APOP %s %s\r\n", e->username, md5buf); email_write(e, buf, size - 1); return; } if (!email_op_ok(ev->data, ev->size)) { ERR("Username invalid!"); ecore_con_server_del(e->svr); return; } size = sizeof(char) * (sizeof("PASS ") - 1 + sizeof("\r\n") - 1 + strlen(e->password)) + 1; buf = alloca(size); snprintf(buf, size, "PASS %s\r\n", e->password); DBG("Sending password"); ecore_con_server_send(e->svr, buf, size - 1); e->state++; return; case EMAIL_STATE_PASS: if (!email_op_ok(ev->data, ev->size)) { ERR("Credentials invalid!"); ecore_con_server_del(e->svr); return; } INF("Logged in successfully!"); e->state++; ecore_event_add(EMAIL_EVENT_CONNECTED, e, (Ecore_End_Cb)email_fake_free, NULL); default: break; } }
Eina_Bool data_pop(Email *e, int type __UNUSED__, Ecore_Con_Event_Server_Data *ev) { char *recv; if (e != ecore_con_server_data_get(ev->server)) { DBG("Event mismatch"); return ECORE_CALLBACK_PASS_ON; } recv = alloca(ev->size + 1); memcpy(recv, ev->data, ev->size); recv[ev->size] = 0; DBG("Receiving %i bytes:\n%s", ev->size, recv); if (e->state < EMAIL_STATE_CONNECTED) { email_login_pop(e, ev); return ECORE_CALLBACK_RENEW; } if (!e->current) return ECORE_CALLBACK_RENEW; switch (e->current) { case EMAIL_OP_STAT: if (!email_pop3_stat_read(e, recv, ev->size)) return ECORE_CALLBACK_RENEW; break; case EMAIL_OP_LIST: if (!email_pop3_list_read(e, ev)) return ECORE_CALLBACK_RENEW; break; case EMAIL_OP_RETR: if (!email_pop3_retr_read(e, ev)) return ECORE_CALLBACK_RENEW; break; case EMAIL_OP_DELE: case EMAIL_OP_QUIT: { Ecore_Cb cb; cb = e->cbs->data; e->cbs = eina_list_remove_list(e->cbs, e->cbs); if (!email_op_ok(ev->data, ev->size)) { if (e->current == EMAIL_OP_DELE) ERR("Error with DELE"); else ERR("Error with QUIT"); } else { if (e->current == EMAIL_OP_DELE) INF("DELE successful"); else INF("QUIT"); } if (cb) cb(e); if (e->current == EMAIL_OP_QUIT) ecore_con_server_del(e->svr); break; } default: break; } next_pop(e); return ECORE_CALLBACK_RENEW; }