#define _XOPEN_SOURCE #include #include #include #include #include #include #include #include #include #include #include "input_gadgets.h" #define fh_temperature_regex "\\s*\n\\s*Wetterdaten vom ([0-9]{2})\\.([0-9]{2})\\.([0-9]{4}) um ([0-9:]{5}) MEZ(.|\n)*>Temperatur\\s*\n\\s*]*>([^<]*)" #define wetter_warnung_filename_regex "^2\\.49\\.0\\.1\\.276\\.0\\.DWD\\.PVW\\.([0-9]+)\\." static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; MemoryStruct *mem = (MemoryStruct *)userp; char *ptr = realloc(mem->memory, mem->size + realsize + 1); if(ptr == NULL) { /* out of memory! */ printf("not enough memory (realloc returned NULL)\n"); return 0; } mem->memory = ptr; memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } int point_is_inside_polygon(double lat, double lon, char *text) { char *input = malloc(strlen(text)+1); if (input == NULL) { fprintf(stderr, "malloc failed to allocate %d bytes\n", strlen(text)+1); return -1; } strcpy(input, text); double *lats = malloc(1); if (lats == NULL) { fprintf(stderr, "malloc failed to allocate 1 byte\n"); free(input); return -1; } double *lons = malloc(1); if (lons == NULL) { fprintf(stderr, "malloc failed to allocate 1 byte\n"); free(lats); free(input); return -1; } int len = 0; int alloc_len = 0; char *q = NULL; char *p = strtok_r(input, ",", &q); while (p != NULL) { if (alloc_len<=len) { double *n; alloc_len = len + 16; n = realloc(lons, alloc_len*sizeof(lons[0])); if (n == NULL) { fprintf(stderr, "malloc failed to allocate %d byte\n", alloc_len*sizeof(lons[0])); free(input); free(lats); free(lons); return -1; } lons = n; n = realloc(lats, alloc_len*sizeof(lats[0])); if (n == NULL) { fprintf(stderr, "malloc failed to allocate %d byte\n", alloc_len*sizeof(lats[0])); free(input); free(lats); free(lons); return -1; } lats = n; } lats[len] = atof(p); p=strtok_r(NULL, " ", &q); if (p == NULL) { fprintf(stderr, "point_is_inside_polygon misses a space\n"); free(input); free(lats); free(lons); return -1; } lons[len] = atof(p); p=strtok_r(NULL, ",", &q); len++; } free(input); if ((lons[0] != lons[len-1]) || (lats[0] != lats[len-1])) { fprintf(stderr, "point_is_inside_polygon was given a non-closed polygon border\n"); free(lats); free(lons); return -1; } int is_inside = 0; for (int i=0; i lats[i]) && (lat >= lats[i+1])) continue; if (lats[i] == lats[i+1]) continue; if ((lat - lats[i]) / (lats[i+1] - lats[i]) * (lons[i+1] - lons[i]) + lons[i] < lon) is_inside = 1 - is_inside; } free(lats); free(lons); return is_inside; } char *gadgets_retrieve_current_temperature(char *output, int max_len) { CURL *curl_handle; CURLcode res; MemoryStruct chunk; int ret_val; chunk.memory = malloc(1); chunk.size = 0; curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); if (!curl_handle) { perror("Failed to init curl"); free(chunk.memory); return NULL; } curl_easy_setopt(curl_handle, CURLOPT_URL, "https://wetter.mb.fh-jena.de/station/datenbank/php_giese/online.php"); curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); res = curl_easy_perform(curl_handle); curl_easy_cleanup(curl_handle); if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); free(chunk.memory); return NULL; } regex_t re; regmatch_t rm[7]; if (regcomp(&re, fh_temperature_regex, REG_EXTENDED|REG_NEWLINE) != 0) { fprintf(stderr, "Failed to compile regex '%s'\n", fh_temperature_regex); free(chunk.memory); return NULL; } if (ret_val = regexec(&re, chunk.memory, 7, rm, 0)) { char *reg_err; reg_err = malloc(1024); regerror(ret_val, &re, reg_err, 1024); fprintf(stderr, "%d %s\n",ret_val,reg_err); regfree(&re); free(chunk.memory); return NULL; } regfree(&re); char* ende; if (max_len > 0) { int i = snprintf(output, max_len, "%.*s (%.*s %.*s-%.*s-%.*s)", (int)(rm[6].rm_eo - rm[6].rm_so), (char*)(chunk.memory + rm[6].rm_so), (int)(rm[4].rm_eo - rm[4].rm_so), (char*)(chunk.memory + rm[4].rm_so), (int)(rm[3].rm_eo - rm[3].rm_so), (char*)(chunk.memory + rm[3].rm_so), (int)(rm[2].rm_eo - rm[2].rm_so), (char*)(chunk.memory + rm[2].rm_so), (int)(rm[1].rm_eo - rm[1].rm_so), (char*)(chunk.memory + rm[1].rm_so) ); ende = output + i; for (; i>=0; i--) if (output[i] == '(') break; for (; i>=0; i--) if (output[i] == '.') output[i] = ','; } else ende = output; free(chunk.memory); return ende; } xmlNode *xml_find_node_by_name(xmlNode *cur_node, char *name) { while (cur_node) { if ((cur_node -> type == XML_ELEMENT_NODE) && (strcmp((char *)cur_node -> name, name) == 0)) return cur_node; cur_node = cur_node -> next; } return NULL; } xmlChar *xml_extract_string(xmlDoc *doc, xmlNode *cur_node, char *name) { xmlNode *sub_node = xml_find_node_by_name(cur_node, name); if (! sub_node) return NULL; else return xmlNodeListGetString(doc, sub_node -> xmlChildrenNode, 0); } char *gadgets_retrieve_weather_forecast(char *output, int max_len) { CURL *curl_handle; CURLcode res; MemoryStruct chunk; int ret_val; chunk.memory = malloc(1); chunk.size = 0; curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); if (!curl_handle) { perror("Failed to init curl"); free(chunk.memory); return NULL; } curl_easy_setopt(curl_handle, CURLOPT_URL, "https://api.met.no/weatherapi/locationforecast/1.9/?lat=50.8830&lon=11.6223&msl=170"); curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); res = curl_easy_perform(curl_handle); curl_easy_cleanup(curl_handle); if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); free(chunk.memory); return NULL; } LIBXML_TEST_VERSION xmlDocPtr doc; doc = xmlReadMemory(chunk.memory, chunk.size, "noname.xml", NULL, 0); free(chunk.memory); if (doc == NULL) { fprintf(stderr, "Failed to parse document\n"); return NULL; } xmlNode *cur_node = NULL; xmlNode *sub_node = NULL; cur_node = xmlDocGetRootElement(doc); if (!cur_node) { fprintf(stderr, "Failed to reach root node of xml\n"); return NULL; } cur_node = xml_find_node_by_name(cur_node, "weatherdata"); if (!cur_node) { fprintf(stderr, "Failed to enter \n"); return NULL; } cur_node = xml_find_node_by_name(cur_node -> children, "product"); if (!cur_node) { fprintf(stderr, "Failed to enter \n"); return NULL; } float rain_total = 0, temp_min = NAN, temp_max = NAN, wind_max = NAN, cur_val; char time_str[2][21]; time_t now; time(&now); now = ((int)(now/60/60))*60*60; for (cur_node = cur_node -> children; cur_node; cur_node = cur_node->next) { if ((cur_node->type == XML_ELEMENT_NODE) && (strcmp((char *)cur_node->name,"time")==0) && (strcmp((char *)xmlGetProp(cur_node,(xmlChar *)"datatype"),"forecast")==0)) { for (int i=0; i<=14; i++) { now += i*60*60; strftime(time_str[0],21,"%Y-%m-%dT%H:%M:%SZ",gmtime(&now)); now += 60*60; strftime(time_str[1],21,"%Y-%m-%dT%H:%M:%SZ",gmtime(&now)); now -= (i+1)*60*60; if ((strcmp(time_str[1],(char *)xmlGetProp(cur_node,(xmlChar *)"from"))==0) && (strcmp(time_str[1],(char *)xmlGetProp(cur_node,(xmlChar *)"to"))==0)) { sub_node = xml_find_node_by_name(cur_node -> children,"location"); cur_val = atof((char *)xmlGetProp(xml_find_node_by_name(sub_node -> children, "temperature"), (xmlChar *)"value")); if (isnan(temp_max) || (cur_val > temp_max)) temp_max = cur_val; if (isnan(temp_min) || (cur_val < temp_min)) temp_min = cur_val; cur_val = atof((char *)xmlGetProp(xml_find_node_by_name(sub_node -> children, "windSpeed"), (xmlChar *)"mps")); if (isnan(wind_max) || (cur_val > wind_max)) wind_max = cur_val; } if ((strcmp(time_str[0],(char *)xmlGetProp(cur_node,(xmlChar *)"from"))==0) && (strcmp(time_str[1],(char *)xmlGetProp(cur_node,(xmlChar *)"to"))==0)) { sub_node = xml_find_node_by_name(cur_node -> children,"location"); if (!sub_node) continue; sub_node = xml_find_node_by_name(sub_node -> children, "precipitation"); if (!sub_node) continue; rain_total += atof((char *)xmlGetProp(sub_node,(xmlChar *)"value")); } } } } xmlFreeDoc(doc); xmlCleanupParser(); if (max_len > 0) { int i = snprintf(output, max_len, "%0.1f ,, %0.1f °C; %0.1f mm; %0.1f m/s", temp_min, temp_max, rain_total, wind_max); char *ende = output + i; for (; i>=0; i--) if (output[i] == '.') output[i] = ','; else if (output[i] == ',') output[i] = '.'; return ende; } else return output; } char *gadgets_retrieve_weather_warnings(char *output, int max_len) { CURL *curl_handle; CURLcode res; MemoryStruct chunk; int ret_val; chunk.memory = malloc(1); chunk.size = 0; curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); if (!curl_handle) { perror("Failed to init curl"); free(chunk.memory); return NULL; } curl_easy_setopt(curl_handle, CURLOPT_URL, "https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_DWD_STAT/Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMDWD_COMMUNEUNION_DE.zip"); curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); res = curl_easy_perform(curl_handle); curl_easy_cleanup(curl_handle); if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); free(chunk.memory); return NULL; } zip_error_t error; zip_source_t *src; zip_t *za; zip_file_t *zf; zip_stat_t zs; zip_error_init(&error); if ((src = zip_source_buffer_create(chunk.memory, chunk.size, 1, &error)) == NULL) { fprintf(stderr, "can't create zip source: %s\n", zip_error_strerror(&error)); zip_error_fini(&error); free(chunk.memory); return NULL; } if ((za = zip_open_from_source(src, 0, &error)) == NULL) { fprintf(stderr, "can't open zip from source: %s\n", zip_error_strerror(&error)); zip_source_free(src); zip_error_fini(&error); free(chunk.memory); return NULL; } zip_error_fini(&error); LIBXML_TEST_VERSION int warnings_len = 0; warning_t *warnings = malloc(sizeof(warning_t)); if (warnings == NULL) { fprintf(stderr, "malloc failed allocating %d bytes\n", sizeof(warning_t)); free(chunk.memory); return NULL; } for (int i=0; i\n"); free(inflated); free(chunk.memory); for (int i=0; i children; text = xml_extract_string(doc, cur_node, "status"); if (text == NULL) { fprintf(stderr, "Failed to enter \n"); free(inflated); free(chunk.memory); for (int i=0; i\n"); free(inflated); free(chunk.memory); for (int i=0; i is neither 'Alert' nor 'Cancel' nor 'Update'\n"); free(chunk.memory); for (int i=0; i\n"); free(inflated); free(chunk.memory); for (int i=0; i children; text = xml_extract_string(doc, cur_node, "category"); if (!text) { fprintf(stderr, "Failed to enter %s\n",zs.name); free(inflated); free(chunk.memory); for (int i=0; i is neither 'Met' nor 'Health'\n"); free(chunk.memory); free(inflated); for (int i=0; i %s\n",zs.name); free(inflated); free(chunk.memory); for (int i=0; i is neither 'Met' nor 'Health'\n"); free(chunk.memory); free(inflated); for (int i=0; i %s\n",zs.name); free(inflated); free(chunk.memory); for (int i=0; i %s\n",zs.name); free(inflated); free(chunk.memory); for (int i=0; i next) { xmlNode *sub_sub_node; for (sub_sub_node = sub_node -> children; sub_sub_node = xml_find_node_by_name(sub_sub_node, "geocode"); sub_sub_node = sub_sub_node -> next) { text = xml_extract_string(doc, sub_sub_node -> children, "valueName"); if (text == NULL) { fprintf(stderr, "Failed to enter \n"); free(inflated); free(chunk.memory); for (int i=0; i children, "value"); if (text == NULL) { fprintf(stderr, "Failed to enter \n"); free(inflated); free(chunk.memory); for (int i=0; i children; sub_sub_node = xml_find_node_by_name(sub_sub_node, "polygon"); sub_sub_node = sub_sub_node -> next) { text = xmlNodeListGetString(doc, sub_sub_node -> children, 0); if (text == NULL) { fprintf(stderr, "Failed to read text of \n"); free(inflated); free(chunk.memory); for (int i=0; i\n"); free(inflated); free(chunk.memory); for (int i=0; i\n"); free(inflated); free(chunk.memory); for (int i=0; i 0)) ende += snprintf(ende, max_len, "%s", "keine Warnungen"); for (int i=0; i 0) { ende += snprintf(ende, output + max_len - ende, "%s", warnings[i].event); if ((i+1 0)) ende += snprintf(ende, output + max_len - ende, "; ", warnings[i].event); } free(warnings[i].headline); free(warnings[i].event); } free(warnings); return ende; }