static void logged_out_callback(sp_session *session) { TRACE("logged_out_callback\n"); struct owl_state* state = sp_session_userdata(session); state->state = OWL_STATE_INITIALIZED; INFO("Logged out from Spotify\n"); respond_success(state->http_request); }
// // -- Spotify callbacks --------------------------------------------------------------------------- // static void logged_in_callback(sp_session *session, sp_error error) { TRACE("logged_in_callback\n"); struct owl_state* state = sp_session_userdata(session); if(error == SP_ERROR_OK) { state->state = OWL_STATE_IDLE; INFO("Logged in to Spotify!\n"); respond_success(state->http_request); } else { state->state = OWL_STATE_INITIALIZED; ERROR("Failed to login to Spotify: %s\n", sp_error_message(error)); respond_error(state->http_request, OWL_HTTP_ERROR_LOGIN, sp_error_message(error)); } }
void handle_client(int fd, const char * userTest, const char * passTest) { FILE * fp = fdopen(fd, "w+"); char * user, * pass, * path; long long initial; if (read_client_request(fp, &user, &pass, &path, &initial) < 0) { return; } if (strcmp(user, userTest) != 0 || strcmp(pass, passTest) != 0) { respond_error(fp, PROTOCOL_ERROR_AUTH, "Login incorrect."); goto handleError; } #ifdef __linux__ struct stat64 info; if (stat64(path, &info) < 0) { #else struct stat info if (stat(path, &info) < 0) { #endif respond_error(fp, PROTOCOL_ERROR_NO_FILE, "Could not stat file."); goto handleError; } if (S_ISDIR(info.st_mode)) { respond_error(fp, PROTOCOL_ERROR_NOT_FILE, "Could not send directory."); goto handleError; } if (initial > info.st_size) { respond_error(fp, PROTOCOL_ERROR_INVALID_INITIAL, "Invalid initial offset."); goto handleError; } #ifdef __linux__ FILE * readFile = fopen64(path, "r"); #else FILE * readfile = fopen(path, "r"); #endif if (!readFile) { perror("fopen"); respond_error(fp, PROTOCOL_ERROR_INTERNAL, "fopen() failed"); goto handleError; } if (respond_success(fp, info.st_size - initial) < 0) { fclose(readFile); goto handleError; } // read file from start offset fseek(readFile, initial, SEEK_SET); char buff[512]; while (!feof(readFile)) { int got = fread(buff, 1, 512, readFile); if (got == 0) break; if (fwrite(buff, 1, got, fp) != got) { break; } } fclose(readFile); handleError: fclose(fp); free(user); free(pass); free(path); return; } void sigchild_handler(int signal) { int status; wait(&status); }
// // Function called when a new HTTP request have been recieved. // static void http_handler(struct evhttp_request *request, void *userdata) { struct owl_state* state = userdata; // Setup general response headers struct evkeyvalq *headers = evhttp_request_get_output_headers(request); evhttp_add_header(headers, "Server", USER_AGENT); // Get the requested URI const char* uri = evhttp_request_get_uri(request); const int http_method = evhttp_request_get_command(request); if( http_method != EVHTTP_REQ_GET && http_method != EVHTTP_REQ_PUT && http_method != EVHTTP_REQ_POST) { evhttp_send_error(request, 501, "Not Implemented"); return; } TRACE("Received HTTP request: %s (method %d)\n", uri, http_method); // Keep the request for async usage state->http_request = request; // // Retrieve application state (sync) if(string_starts_with(uri, "/api/state") && http_method == EVHTTP_REQ_GET) { state_action(state); } // // Shutdown owl application (async) else if(string_starts_with(uri, "/api/shutdown") && http_method == EVHTTP_REQ_GET) { shutdown_action(state); } // // Try to login to Spotify (async) else if(string_starts_with(uri, "/api/login") && http_method == EVHTTP_REQ_GET) { char* username = extract_uri_section(2, uri); char* password = extract_uri_section(3, uri); if(username != NULL && password != NULL) { login_to_spotify_action(state, username, password); } else { WARN("Could not extract username and password in order to login to Spotify!\n"); respond_error(request, OWL_HTTO_ERROR_NO_LOGIN_DETAILS, "No username or password given"); } } else if(string_starts_with(uri, "/api/login") && http_method == EVHTTP_REQ_POST) { TRACE("POST LOGIN\n"); get_post_argument(request, "username"); evhttp_send_error(request, 501, "Not Implemented"); } // // Logout from spotify (async) else if(string_starts_with(uri, "/api/logout") && http_method == EVHTTP_REQ_GET) { if(state->state > OWL_STATE_LOGGING_IN && state->state < OWL_STATE_LOGGING_OUT) logout_from_spotify_action(state); else respond_success(request); } // // Clear the entire queue else if(string_starts_with(uri, "/api/queue/clear") && http_method == EVHTTP_REQ_GET) { if(state->state < OWL_STATE_IDLE || state->state > OWL_STATE_PLAYING) { respond_error(request, OWL_HTTP_ERROR_NOT_LOGGED_IN, "Operation not allowed when not logged in"); } else { const int size = queue_size(state->spotify_state->queue); for(int i = 0; i < size; i++) { owl_track *track = pop_from_queue(state->spotify_state->queue); free_track(track); } respond_success(request); } } // // Get the current playback queue (sync) else if(string_starts_with(uri, "/api/queue") && http_method == EVHTTP_REQ_GET) { if(state->state < OWL_STATE_IDLE || state->state > OWL_STATE_PLAYING) { WARN("Operation not allowed at this state (%d)\n", state->state); respond_error(request, OWL_HTTP_ERROR_NOT_LOGGED_IN, "Operation not allowed when not logged in"); } else { respond_with_queue(state->http_request, state->spotify_state->queue); } } // // Serve static file immediately else { // Create the buffer to retrn as content struct evbuffer *content_buffer = evbuffer_new(); // If not a handler this is a static request char *static_file = (char *) malloc(strlen(doc_root) + strlen(uri) + 1); stpcpy(stpcpy(static_file, doc_root), uri); TRACE("Looking for static file: %s\n", static_file); bool file_exists = 1; struct stat st; if(stat(static_file, &st) == -1 || S_ISDIR(st.st_mode)) { file_exists = 0; evhttp_send_error(request, HTTP_NOTFOUND, "Not Found"); } if(file_exists) { const int file_size = st.st_size; FILE *fp = fopen(static_file, "r"); const char* content_type = resolve_content_type(static_file); evbuffer_add_file(content_buffer, fileno(fp), 0, file_size); // will close TRACE("Resolving content type for filename: %s to: %s\n", static_file, content_type); evhttp_add_header(headers, "Content-Type", content_type); evhttp_send_reply(request, HTTP_OK, "OK", content_buffer); } free(static_file); // Send the data evhttp_send_reply(request, HTTP_OK, USER_AGENT, content_buffer); // Free memrory evbuffer_free(content_buffer); } return; }