static int callback_lws_table_dirlisting(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__tbl_dir *pss = (struct per_session_data__tbl_dir *)user; char j[LWS_PRE + 16384], *p = j + LWS_PRE, *start = p, *q, *q1, *w, *end = j + sizeof(j) - LWS_PRE, e[384], s[384], s1[384]; const struct lws_protocol_vhost_options *pmo; struct fobj *f; int n, first = 1; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ break; case LWS_CALLBACK_ESTABLISHED: lwsl_debug("LWS_CALLBACK_ESTABLISHED\n"); /* * send client the lwsgt table layout */ start = "{\"cols\":[" " {\"name\": \"Date\"}," " {\"name\": \"Size\", \"align\": \"right\"}," " {\"name\": \"Icon\"}," " {\"name\": \"Name\", \"href\": \"uri\"}," " {\"name\": \"uri\", \"hide\": \"1\" }" " ]" "}"; if (lws_write(wsi, (unsigned char *)start, strlen(start), LWS_WRITE_TEXT) < 0) return -1; /* send a view update next */ lws_callback_on_writable(wsi); break; case LWS_CALLBACK_RECEIVE: if (len > sizeof(pss->reldir) - 1) len = sizeof(pss->reldir) - 1; if (!strstr(in, "..") && !strchr(in, '~')) strncpy(pss->reldir, in, len); else len = 0; pss->reldir[len] = '\0'; if (pss->reldir[0] == '/' && !pss->reldir[1]) pss->reldir[0] = '\0'; lwsl_info("%s\n", pss->reldir); lws_callback_on_writable(wsi); break; case LWS_CALLBACK_SERVER_WRITEABLE: if (scan_dir(wsi, pss)) return 1; p += lws_snprintf(p, end - p, "{\"breadcrumbs\":["); q = pss->reldir; if (!q[0]) p += lws_snprintf(p, end - p, "{\"name\":\"top\"}"); while (*q) { q1 = strchr(q, '/'); if (!q1) { if (first) strcpy(s, "top1"); else strcpy(s, q); s1[0] = '\0'; q += strlen(q); } else { n = lws_ptr_diff(q1, q); if (n > (int)sizeof(s) - 1) n = sizeof(s) - 1; if (first) { strcpy(s1, "/"); strcpy(s, "top"); } else { strncpy(s, q, n); s[n] = '\0'; n = lws_ptr_diff(q1, pss->reldir); if (n > (int)sizeof(s1) - 1) n = sizeof(s1) - 1; strncpy(s1, pss->reldir, n); s1[n] = '\0'; } q = q1 + 1; } if (!first) p += lws_snprintf(p, end - p, ","); else first = 0; p += lws_snprintf(p, end - p, "{\"name\":\"%s\"", lws_json_purify(e, s, sizeof(e))); if (*q) { w = s1; while (w[0] == '/' && w[1] == '/') w++; p += lws_snprintf(p, end - p, ",\"url\":\"%s\"", lws_json_purify(e, w, sizeof(e))); } p += lws_snprintf(p, end - p, "}"); if (!q1) break; } p += lws_snprintf(p, end - p, "],\"data\":["); f = pss->base.next; while (f) { /* format in JSON */ p += lws_snprintf(p, end - p, "{\"Icon\":\"%s\",", lws_json_purify(e, f->icon, sizeof(e))); p += lws_snprintf(p, end - p, " \"Date\":\"%s\",", lws_json_purify(e, f->date, sizeof(e))); p += lws_snprintf(p, end - p, " \"Size\":\"%ld\",", f->size); if (f->uri) p += lws_snprintf(p, end - p, " \"uri\":\"%s\",", lws_json_purify(e, f->uri, sizeof(e))); p += lws_snprintf(p, end - p, " \"Name\":\"%s\"}", lws_json_purify(e, f->name, sizeof(e))); f = f->next; if (f) p += lws_snprintf(p, end - p, ","); } p += lws_snprintf(p, end - p, "]}"); free_scan_dir(pss); if (lws_write(wsi, (unsigned char *)start, p - start, LWS_WRITE_TEXT) < 0) return -1; break; case LWS_CALLBACK_HTTP_PMO: /* find the per-mount options we're interested in */ lwsl_debug("LWS_CALLBACK_HTTP_PMO\n"); pmo = (struct lws_protocol_vhost_options *)in; while (pmo) { if (!strcmp(pmo->name, "dir")) /* path to list files */ pss->dir = pmo->value; pmo = pmo->next; } if (!pss->dir[0]) { lwsl_err("dirlisting: \"dir\" pmo missing\n"); return 1; } break; case LWS_CALLBACK_HTTP_DROP_PROTOCOL: //lwsl_notice("LWS_CALLBACK_HTTP_DROP_PROTOCOL\n"); #if UV_VERSION_MAJOR > 0 lws_protocol_dir_kill_monitor(pss); #endif break; default: return 0; } return 0; }
static int callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__gs_mb *pss = (struct per_session_data__gs_mb *)user; const struct lws_protocol_vhost_options *pvo; struct per_vhost_data__gs_mb *vhd = (struct per_vhost_data__gs_mb *) lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)); unsigned char *p, *start, *end, buffer[LWS_PRE + 256]; char s[512]; int n; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct per_vhost_data__gs_mb)); if (!vhd) return 1; vhd->vh = lws_get_vhost(wsi); vhd->gsp = lws_vhost_name_to_protocol(vhd->vh, "protocol-generic-sessions"); if (!vhd->gsp) { lwsl_err("messageboard: requires generic-sessions\n"); return 1; } pvo = (const struct lws_protocol_vhost_options *)in; while (pvo) { if (!strcmp(pvo->name, "message-db")) strncpy(vhd->message_db, pvo->value, sizeof(vhd->message_db) - 1); pvo = pvo->next; } if (!vhd->message_db[0]) { lwsl_err("messageboard: \"message-db\" pvo missing\n"); return 1; } if (sqlite3_open_v2(vhd->message_db, &vhd->pdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) { lwsl_err("Unable to open message db %s: %s\n", vhd->message_db, sqlite3_errmsg(vhd->pdb)); return 1; } if (sqlite3_exec(vhd->pdb, "create table if not exists msg (" " idx integer primary key, time integer," " username varchar(32), email varchar(100)," " ip varchar(80), content blob);", NULL, NULL, NULL) != SQLITE_OK) { lwsl_err("Unable to create msg table: %s\n", sqlite3_errmsg(vhd->pdb)); return 1; } vhd->last_idx = get_last_idx(vhd); break; case LWS_CALLBACK_PROTOCOL_DESTROY: if (vhd->pdb) sqlite3_close(vhd->pdb); goto passthru; case LWS_CALLBACK_ESTABLISHED: vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO, pss->pss_gs, &pss->sinfo, 0); if (!pss->sinfo.username[0]) { lwsl_notice("messageboard ws attempt with no session\n"); return -1; } lws_callback_on_writable(wsi); break; case LWS_CALLBACK_SERVER_WRITEABLE: { struct message m; char j[MAX_MSG_LEN + 512], e[MAX_MSG_LEN + 512], *p = j + LWS_PRE, *start = p, *end = j + sizeof(j) - LWS_PRE; if (pss->last_idx == vhd->last_idx) break; /* restrict to last 10 */ if (!pss->last_idx) if (vhd->last_idx >= 10) pss->last_idx = vhd->last_idx - 10; sprintf(s, "select idx, time, username, email, ip, content " "from msg where idx > %lu order by idx limit 1;", pss->last_idx); if (sqlite3_exec(vhd->pdb, s, lookup_cb, &m, NULL) != SQLITE_OK) { lwsl_err("Unable to lookup msg: %s\n", sqlite3_errmsg(vhd->pdb)); return 0; } /* format in JSON */ p += snprintf(p, end - p, "{\"idx\":\"%lu\",\"time\":\"%lu\",", m.idx, m.time); p += snprintf(p, end - p, " \"username\":\"%s\",", lws_json_purify(e, m.username, sizeof(e))); p += snprintf(p, end - p, " \"email\":\"%s\",", lws_json_purify(e, m.email, sizeof(e))); p += snprintf(p, end - p, " \"ip\":\"%s\",", lws_json_purify(e, m.ip, sizeof(e))); p += snprintf(p, end - p, " \"content\":\"%s\"}", lws_json_purify(e, m.content, sizeof(e))); if (lws_write(wsi, (unsigned char *)start, p - start, LWS_WRITE_TEXT) < 0) return -1; pss->last_idx = m.idx; if (pss->last_idx == vhd->last_idx) break; lws_callback_on_writable(wsi); /* more to do */ } break; case LWS_CALLBACK_HTTP: pss->our_form = 0; /* ie, it's our messageboard new message form */ if (!strcmp((const char *)in, "/msg")) { pss->our_form = 1; break; } goto passthru; case LWS_CALLBACK_HTTP_BODY: if (!pss->our_form) goto passthru; if (len < 2) break; if (!pss->spa) { pss->spa = lws_spa_create(wsi, param_names, ARRAY_SIZE(param_names), MAX_MSG_LEN + 1024, NULL, NULL); if (!pss->spa) return -1; } if (lws_spa_process(pss->spa, in, len)) { lwsl_notice("spa process blew\n"); return -1; } break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: if (!pss->our_form) goto passthru; if (post_message(wsi, vhd, pss)) return -1; p = buffer + LWS_PRE; start = p; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(wsi, 200, &p, end)) return -1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/plain", 10, &p, end)) return -1; if (lws_add_http_header_content_length(wsi, 1, &p, end)) return -1; if (lws_finalize_http_header(wsi, &p, end)) return -1; n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); if (n != (p - start)) { lwsl_err("_write returned %d from %d\n", n, (p - start)); return -1; } s[0] = '0'; n = lws_write(wsi, (unsigned char *)s, 1, LWS_WRITE_HTTP); if (n != 1) return -1; goto try_to_reuse; case LWS_CALLBACK_HTTP_BIND_PROTOCOL: if (!pss || pss->pss_gs) break; pss->pss_gs = malloc(vhd->gsp->per_session_data_size); if (!pss->pss_gs) return -1; memset(pss->pss_gs, 0, vhd->gsp->per_session_data_size); break; case LWS_CALLBACK_HTTP_DROP_PROTOCOL: if (vhd->gsp->callback(wsi, reason, pss ? pss->pss_gs : NULL, in, len)) return -1; if (pss && pss->spa) { lws_spa_destroy(pss->spa); pss->spa = NULL; } if (pss && pss->pss_gs) { free(pss->pss_gs); pss->pss_gs = NULL; } break; default: passthru: return vhd->gsp->callback(wsi, reason, pss ? pss->pss_gs : NULL, in, len); } return 0; try_to_reuse: if (lws_http_transaction_completed(wsi)) return -1; return 0; }