#include #include #include #include #include #include #include #include "cJSON.h" #include "fetch.h" #include "image.h" #define UNUSED(x) (void)x #define OMDB_URL "http://www.omdbapi.com" #define PROJECT_NAME "omdb" /* Default to plain output. */ static enum _output_format { OUTPUT_JSON, OUTPUT_PLAIN, OUTPUT_FANCY } output_format = OUTPUT_PLAIN; static struct option opts[] = {{"id", no_argument, NULL, 'i'}, {"json", no_argument, NULL, 'j'}, {"api-key", required_argument, NULL, 'k'}, {"search-type", required_argument, NULL, 't'}, {NULL, 0, NULL, 0}}; void print_usage(void) { printf( PROJECT_NAME " [ikt] \n" "\t-i/--id: Search by ID rather than title. (optional)\n" "\t-j/--json: Output full JSON response.\n" "\t-k/--api-key: OMDB API Key. (required)\n" "\t-t/--search-type: Search type. (optional) [movie, series, episode]\n"); } /* Set a URL query parameter. */ void set_param(CURLU *restrict url, const char *restrict key, char *restrict value) { CURLUcode err; char param[2048]; snprintf(param, sizeof param, "%s=%s", key, value); if ((err = curl_url_set(url, CURLUPART_QUERY, param, CURLU_APPENDQUERY | CURLU_URLENCODE)) != CURLUE_OK) { fprintf(stderr, "Error setting url param '%s': %s\n", key, curl_url_strerror(err)); exit(EXIT_FAILURE); } } /* Just print the url if needed for debugging. */ void print_url(CURLU *restrict url) { char *url_string = NULL; curl_url_get(url, CURLUPART_URL, &url_string, 0); printf("%s\n", url_string); curl_free(url_string); } /* Print entire JSON response as is. */ int print_title_json(const cJSON *const json) { char *json_str = cJSON_Print(json); if (!json_str) { fputs("Couldn't output formatted JSON.\n", stderr); return -1; } fputs(json_str, stdout); putchar('\n'); free(json_str); return 0; } /* Print some title information in plain text. */ int print_title_plain(const cJSON *json) { cJSON *title = cJSON_GetObjectItem(json, "title"); cJSON *imdb_rating = cJSON_GetObjectItem(json, "imdbRating"); if (title == NULL || imdb_rating == NULL) { printf("Could not find title or rating in response.\n"); return -1; } printf("Found: '%s' with rating of %s\n", title->valuestring, imdb_rating->valuestring); return 0; } int handle_response(struct response *restrict resp) { cJSON *json = NULL; if (strstr(resp->content_type, "application/json") == NULL) { fprintf(stderr, "Unexpected response: %s\n", resp->content_type); return -1; } json = cJSON_ParseWithLength(resp->data, resp->size); if (json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { fprintf(stderr, "Error before: %s\n", error_ptr); } return -1; } switch (output_format) { case OUTPUT_PLAIN: print_title_plain(json); break; case OUTPUT_JSON: print_title_json(json); break; case OUTPUT_FANCY: /* Just print_title + image planned here for now */ print_title_plain(json); break; } cJSON_free(json); return 0; } int main(int argc, char **argv) { int ch; bool k_flag = false; char search_mode[8] = "movie"; if (argc == 0) { fputs("Argument required.\n", stderr); print_usage(); exit(EXIT_FAILURE); } /* Just validate and add options directly to the request now. */ CURLU *url = curl_url(); CURLUcode ures; if (url == NULL) { fputs("Out of memory.\n", stderr); exit(EXIT_FAILURE); } if ((ures = curl_url_set(url, CURLUPART_URL, OMDB_URL, 0)) != CURLUE_OK) { fprintf(stderr, "Couldn't set url: %s\n", curl_url_strerror(ures)); exit(EXIT_FAILURE); } while ((ch = getopt_long(argc, argv, "hijk:t:", opts, NULL)) != -1) { switch (ch) { case 'i': /* Lookup by ID */ set_param(url, "id", optarg); break; case 'j': output_format = OUTPUT_JSON; break; case 'k': /* API Key */ k_flag = true; set_param(url, "apikey", optarg); break; case 't': /* Type: movie, series, episode */ strlcpy(search_mode, optarg, sizeof search_mode); break; case '?': fprintf(stderr, "Invalid option'%c'.\n", optopt); exit(EXIT_FAILURE); case 'h': default: print_usage(); exit(EXIT_FAILURE); } } argc -= optind; if (!k_flag) { fputs("Missing required arguments.\n", stderr); exit(EXIT_FAILURE); } printf("Looking for: %s\n", argv[optind]); /* Set remaining params if any... */ set_param(url, "type", search_mode); set_param(url, "r", "json"); /* Just testing... */ set_param(url, "t", argv[optind]); /* Print it... */ print_url(url); /* * All of the call setup should be done via the URL so all that's left is to * send the request and conditionally handle any response. */ struct fetch *f = fetch_init(); /* Check this */ struct response *resp = fetch(f, url); handle_response(resp); process_image("./test.jpg"); free(resp->data); free(resp); curl_url_cleanup(url); fetch_cleanup(f); return 0; }