utilities.c (15626B)
1 /* 2 (c) 2009 by Leon Winter 3 (c) 2009-2012 by Hannes Schueller 4 (c) 2009-2010 by Matto Fransen 5 (c) 2010-2011 by Hans-Peter Deifel 6 (c) 2010-2011 by Thomas Adam 7 see LICENSE file 8 */ 9 10 11 #include <Elementary.h> 12 #include <EWebKit2.h> 13 14 #include "viking_state.h" 15 #include "viking.h" 16 #include "commands.h" 17 #include "utilities.h" 18 #include "keymap.h" 19 #include "jsmn.h" 20 21 22 void parse(const char *buf); 23 24 char *strdup_printf(const char *fmt, ...) 25 { 26 va_list args; 27 va_start (args,fmt); 28 29 /* arbitrary size */ 30 char *buf = malloc(1024); 31 32 vsnprintf(buf, 1024, fmt, args); 33 va_end(args); 34 35 return buf; 36 } 37 38 void save_command_history(Eina_Stringshare *line, Window_Data *wd) 39 { 40 const char *c = line; 41 42 while (isspace(*c) && *c) 43 c++; 44 if (!strlen(c)) 45 return; 46 47 if (COMMANDHISTSIZE <= eina_list_count(wd->commandhistory)) { 48 /* if list is too long - remove items from beginning */ 49 wd->commandhistory = eina_list_remove(wd->commandhistory, eina_list_nth(wd->commandhistory, 0)); 50 } 51 52 wd->commandhistory = eina_list_append(wd->commandhistory, c); 53 } 54 55 Eina_List * 56 make_keyslist(void) 57 { 58 int i; 59 Eina_List *keylistroot = NULL; 60 61 i = 0; 62 while ( keys[i].key != 0 ) { 63 keylistroot = eina_list_append(keylistroot, &keys[i]); 64 i++; 65 } 66 67 printf("make_keylist() processed %i keys.\n", i); 68 return keylistroot; 69 } 70 71 Eina_Bool 72 parse_colour(char *color) { 73 char goodcolor[8]; 74 int colorlen; 75 76 colorlen = (int)strlen(color); 77 78 goodcolor[0] = '#'; 79 goodcolor[7] = '\0'; 80 81 /* help the user a bit by making string like 82 #a10 and strings like ffffff full 6digit 83 strings with # in front :) 84 */ 85 86 if (color[0] == '#') { 87 switch (colorlen) { 88 case 7: 89 strncpy(goodcolor, color, 7); 90 break; 91 case 4: 92 goodcolor[1] = color[1]; 93 goodcolor[2] = color[1]; 94 goodcolor[3] = color[2]; 95 goodcolor[4] = color[2]; 96 goodcolor[5] = color[3]; 97 goodcolor[6] = color[3]; 98 break; 99 case 2: 100 goodcolor[1] = color[1]; 101 goodcolor[2] = color[1]; 102 goodcolor[3] = color[1]; 103 goodcolor[4] = color[1]; 104 goodcolor[5] = color[1]; 105 goodcolor[6] = color[1]; 106 break; 107 } 108 } else { 109 switch (colorlen) { 110 case 6: 111 strncpy(&goodcolor[1], color, 6); 112 break; 113 case 3: 114 goodcolor[1] = color[0]; 115 goodcolor[2] = color[0]; 116 goodcolor[3] = color[1]; 117 goodcolor[4] = color[1]; 118 goodcolor[5] = color[2]; 119 goodcolor[6] = color[2]; 120 break; 121 case 1: 122 goodcolor[1] = color[0]; 123 goodcolor[2] = color[0]; 124 goodcolor[3] = color[0]; 125 goodcolor[4] = color[0]; 126 goodcolor[5] = color[0]; 127 goodcolor[6] = color[0]; 128 break; 129 } 130 } 131 132 if (strlen (goodcolor) != 7) { 133 return EINA_FALSE; 134 } else { 135 strncpy(color, goodcolor, 8); 136 return EINA_TRUE; 137 } 138 } 139 140 Eina_Bool 141 process_line_arg(const Arg *arg, void *data) { 142 Window_Data *wd = data; 143 return process_line(arg->s, wd); 144 } 145 146 void 147 set_error(const char *error, void *data) 148 { 149 Window_Data *wd = data; 150 /* it should never happen that set_error is called more than once, 151 * but to avoid any potential memory leaks, we ignore any subsequent 152 * error if the current one has not been shown */ 153 if (wd->error_msg == NULL) { 154 wd->error_msg = strdup_printf("%s", error); 155 } 156 } 157 158 void 159 give_feedback(const char *feedback, void *data) 160 { 161 Arg a = { .i = Info }; 162 163 a.s = strdup_printf("%s", feedback); 164 echo(&a, data); 165 free(a.s); 166 } 167 168 Eina_Bool 169 process_line(const char *line, Window_Data *wd) 170 { 171 Eina_Stringshare *cmd_hist; 172 int i; 173 const char *c = line; 174 size_t len, length = strlen(line); 175 Eina_Bool found = EINA_FALSE, success = EINA_FALSE; 176 Arg a; 177 178 while (isspace(*c)) 179 c++; 180 /* Ignore blank lines. */ 181 if (c[0] == '\0') 182 return EINA_TRUE; 183 184 cmd_hist = eina_stringshare_add(c); 185 for (i = 0; i < LENGTH(commands); i++) { 186 if (commands[i].cmd == NULL) 187 break; 188 len = strlen(commands[i].cmd); 189 if (length >= len && !strncmp(c, commands[i].cmd, len) && (c[len] == ' ' || !c[len])) { 190 found = EINA_TRUE; 191 a.i = commands[i].arg.i; 192 //printf("length, len, c, commands[i].arg.s = %zu, %zu, %s, %s\n", 193 // length, len, c, commands[i].arg.s); 194 if (length > len + 1) 195 a.s = strdup(&c[len + 1]); 196 else if (!(length > len + 1) && commands[i].arg.s) 197 a.s = strdup(commands[i].arg.s); 198 else 199 a.s = NULL; 200 success = commands[i].func(&a, wd); 201 free(a.s); 202 break; 203 } 204 } 205 206 save_command_history(cmd_hist, wd); 207 208 if (!found) { 209 a.i = Error; 210 a.s = strdup_printf("Not a browser command: %s", c); 211 echo(&a, wd); 212 free(a.s); 213 } else if (!success) { 214 a.i = Error; 215 if (wd->error_msg != NULL) { 216 a.s = strdup_printf("%s", wd->error_msg); 217 free(wd->error_msg); 218 wd->error_msg = NULL; 219 } else { 220 a.s = strdup_printf("Unknown error. Please file a bug report!"); 221 } 222 echo(&a, wd); 223 free(a.s); 224 } 225 return success; 226 } 227 228 void 229 parse(const char *buf) 230 { 231 int r, i; 232 jsmn_parser p; 233 jsmntok_t tok[10]; 234 235 jsmn_init(&p); 236 r = jsmn_parse(&p, buf, tok, 10); 237 238 if (r != JSMN_SUCCESS) 239 return; 240 241 for (i = 0; i < 10; i++) { 242 // printf("token %i starts @ %i, ends @ %i, size %i, type %i\n", i, tok[i].start, tok[i].end, tok[i].size, tok[i].type); 243 char *tmp = strndup(buf + tok[i].start, tok[i].end - tok[i].start); 244 // printf("token %i = %s\n", i, tmp); 245 free(tmp); 246 } 247 248 // printf("parser pos is %i\n", p.pos); 249 250 } 251 252 void 253 userscript_hooks_start(const char *uri) 254 { 255 // const char *js; 256 int r; 257 258 printf("userscript_hooks_start() uri = %s\n", uri); 259 260 char *base_dir = "/home/kyle/.config/evi/userscript/"; 261 // Eina_List *files_to_parse; 262 Eina_List *l; 263 Eina_List *userscript_dir = ecore_file_ls(base_dir); 264 char *path; 265 char full_path[1024] = ""; 266 267 EINA_LIST_FOREACH(userscript_dir, l, path) { 268 269 memset(full_path, 0, 1024); 270 strcat(full_path, base_dir); 271 strcat(full_path, path); 272 273 if (ecore_file_is_dir(full_path)) { 274 strcat(full_path, "/manifest.json"); 275 276 if (ecore_file_can_read(full_path)) { 277 278 printf("parsing %s ...\n", full_path); 279 280 FILE *fp = fopen(full_path, "r"); 281 fseek(fp, 0L, SEEK_END); 282 int len = ftell(fp); 283 char *buf = malloc(len); 284 rewind(fp); 285 r = fread(buf, len, 1, fp); 286 fclose(fp); 287 288 parse(buf); 289 290 if (!r) 291 free(buf); 292 // files_to_parse = eina_list_append(files_to_parse, full_path); 293 // printf("would have parsed %s\n", full_path); 294 } 295 } 296 } 297 298 /* 299 Evas_Object *frame = ewk_view_frame_main_get(bd->view); 300 FILE *fp = fopen("/home/kyle/.config/viking/userscript/adblockplus/contentScript1.js", "r"); 301 if (!fp) 302 printf("error opening file.\n"); 303 fseek(fp, 0L, SEEK_END); 304 int len = ftell(fp); 305 char *buf = malloc(len); 306 rewind(fp); 307 fread(buf, len, 1, fp); 308 fclose(fp); 309 ewk_frame_script_execute(frame, buf); 310 printf("uri_changed() executed %i byte script %s\n", len, "contentScript1.js"); 311 free(buf); 312 313 Evas_Object *frame = ewk_view_frame_main_get(td->view); 314 char *scripts[15] = { 315 "tampermonkey/src/emulation.js", 316 "tampermonkey/src/environment.js", 317 318 "tampermonkey/src/registry.js", 319 "tampermonkey/src/convert.js", 320 "tampermonkey/src/helper.js", 321 "tampermonkey/src/xmlhttprequest.js", 322 "tampermonkey/src/content.js", 323 324 "reddit-enhancement-suite/jquery-1.6.4.min.js", 325 "reddit-enhancement-suite/guiders-1.2.8.js", 326 "reddit-enhancement-suite/jquery.dragsort-0.4.3.min.js", 327 "reddit-enhancement-suite/jquery-fieldselection.min.js", 328 "reddit-enhancement-suite/tinycon.min.js", 329 "reddit-enhancement-suite/jquery.tokeninput.js", 330 "reddit-enhancement-suite/reddit_enhancement_suite.user.js", 331 332 }; 333 334 for (i = 0; i < 14; i++) { 335 char *path = strdup_printf("/home/kyle/.config/viking/userscript/%s", scripts[i]); 336 FILE *fp = fopen(path, "r"); 337 free(path); 338 if (!fp) 339 printf("error opening file.\n"); 340 fseek(fp, 0L, SEEK_END); 341 int len = ftell(fp); 342 char *buf = malloc(len); 343 rewind(fp); 344 fread(buf, len, 1, fp); 345 fclose(fp); 346 ewk_frame_script_execute(frame, buf); 347 printf("uri_changed() executed %i byte script %s\n", len, scripts[i]); 348 free(buf); 349 } 350 */ 351 } 352 353 void 354 userscript_hooks_end(const char *uri) 355 { 356 /* 357 Evas_Object *frame = ewk_view_frame_main_get(bd->view); 358 FILE *fp = fopen("/home/kyle/.config/viking/userscript/adblockplus/contentScript2.js", "r"); 359 if (!fp) 360 printf("error opening file.\n"); 361 fseek(fp, 0L, SEEK_END); 362 int len = ftell(fp); 363 char *buf = malloc(len); 364 rewind(fp); 365 fread(buf, len, 1, fp); 366 fclose(fp); 367 ewk_frame_script_execute(frame, buf); 368 printf("load_finished() executed %i byte script\n", len); 369 free(buf); 370 */ 371 } 372 373 void 374 setup_modkeys(void *data) 375 { 376 App_Data *ad = data; 377 unsigned int i; 378 379 ad->modkeys = calloc(LENGTH(keys) + 1, sizeof(char)); 380 ad->modkeys[0] = '\0'; 381 382 for (i = 0; i < LENGTH(keys); i++) { 383 if (keys[i].modkey && !strchr(ad->modkeys, keys[i].modkey)) { 384 // strcat(ad->modkeys, keys[i].modkey); 385 ad->modkeys[strlen(ad->modkeys)] = keys[i].modkey; 386 ad->modkeys[strlen(ad->modkeys) + 1] = '\0'; 387 } 388 } 389 // fprintf(stderr, "Modkey array looks like %s\n", ad->modkeys); 390 } 391 392 Eina_Bool 393 echo(const Arg *arg, void *data) 394 { 395 Window_Data *ad = data; 396 int index = !arg->s ? 0 : arg->i & (~NoAutoHide); 397 398 printf("echo() index = %i\n", index); 399 400 if (index < Info || index > Error) 401 return EINA_TRUE; 402 403 // if (!elm_object_focus_get(ad->url)) 404 elm_entry_entry_set(ad->url, !arg->s ? "" : arg->s); 405 406 return EINA_TRUE; 407 } 408 409 void 410 gui_count_update(Window_Data *wd) 411 { 412 Eina_Strbuf *status = eina_strbuf_new(); 413 414 eina_strbuf_append_printf(status, "%.0d", wd->count); 415 elm_object_text_set(wd->status_count, eina_strbuf_string_steal(status)); 416 } 417 418 void 419 gui_modkey_update(Window_Data *wd) 420 { 421 Eina_Strbuf *status = eina_strbuf_new(); 422 423 if (wd->current_modkey) 424 eina_strbuf_append(status, &wd->current_modkey); 425 elm_object_text_set(wd->status_modkey, eina_strbuf_string_steal(status)); 426 } 427 428 void 429 gui_zoom_update(Window_Data *wd, float zoom) 430 { 431 Eina_Strbuf *status = eina_strbuf_new(); 432 433 if (zoom != 1.0) 434 eina_strbuf_append_printf(status, " %0.2lfx", zoom); 435 elm_object_text_set(wd->status_zoom, eina_strbuf_string_steal(status)); 436 } 437 438 void 439 gui_scroll_update(Window_Data *wd) 440 { 441 /* 442 Eina_Strbuf *buf = eina_strbuf_new(); 443 int x, y, w, h, val; 444 445 evas_object_geometry_get(wd->cur_buf->view, &x, &y, &w, &h); 446 printf("scroll_update() %i, %i, %i, %i\n", x, y, w, h); 447 ewk_frame_scroll_pos_get(frame, &x, &y); 448 ewk_frame_scroll_size_get(frame, &w, &h); 449 450 val = (int) ((float) y / h * 100); 451 452 if (h == 0) 453 eina_strbuf_append(status, " All"); 454 else if (val == 0) 455 eina_strbuf_append(status, " Top"); 456 else if (val == 100) 457 eina_strbuf_append(status, " Bot"); 458 else 459 eina_strbuf_append_printf(status, " %d%%", val); 460 461 */ 462 elm_object_text_set(wd->status_scroll, "Unk"); 463 } 464 465 #if 0 466 Eina_Bool 467 enable_proxy(Buffer_Data *bd) 468 { 469 SoupURI *soup_uri; 470 char *proxy_uri, *new; 471 472 printf("trying to enable proxy .. "); 473 474 proxy_uri = getenv("http_proxy"); 475 if (proxy_uri == NULL) 476 proxy_uri = getenv("HTTP_PROXY"); 477 478 if (proxy_uri != NULL && 0 < strlen(proxy_uri)) { 479 new = strstr(proxy_uri, "http://") ? 480 strdup(proxy_uri) : strdup_printf("http://%s", proxy_uri); 481 482 soup_uri = soup_uri_new(new); 483 /* really wish there was per-view proxy support in webkit */ 484 g_object_set(bd->window->app->soup_session, "proxy-uri", soup_uri, NULL); 485 486 printf("success! (%s)\n", new); 487 bd->proxy_enabled = EINA_TRUE; 488 489 soup_uri_free(soup_uri); 490 free(new); 491 return EINA_TRUE; 492 } 493 else { 494 printf("HTTP_PROXY not set.\n"); 495 return EINA_FALSE; 496 } 497 } 498 #endif 499 500 /* 501 void 502 set_widget_font_and_color(Evas_Object *widget, const char *font_str, const char *bg_color_str, const char *fg_color_str) 503 { 504 GdkColor fg_color; 505 GdkColor bg_color; 506 PangoFontDescription *font; 507 508 font = pango_font_description_from_string(font_str); 509 gtk_widget_modify_font(widget, font); 510 pango_font_description_free(font); 511 512 if (fg_color_str) 513 gdk_color_parse(fg_color_str, &fg_color); 514 if (bg_color_str) 515 gdk_color_parse(bg_color_str, &bg_color); 516 517 gtk_widget_modify_text(widget, GTK_STATE_NORMAL, fg_color_str ? &fg_color : NULL); 518 gtk_widget_modify_base(widget, GTK_STATE_NORMAL, bg_color_str ? &bg_color : NULL); 519 520 return; 521 } 522 */ 523 524 void 525 make_buffer_number(Evas_Object *label, Buffer_Data *bd) 526 { 527 Eina_Strbuf *buf = eina_strbuf_new(); 528 529 evas_object_size_hint_align_set(label, 0.0, EVAS_HINT_FILL); 530 eina_strbuf_append_printf(buf, " %2i ", bd->buf_number); 531 elm_object_text_set(label, eina_strbuf_string_steal(buf)); 532 evas_object_show(label); 533 } 534 535 static void 536 received_favicon_cb(const char *url, Evas_Object *icon, void *data) 537 { 538 Evas_Object *old_icon; 539 Eina_List *l; 540 Evas_Object *row = data; 541 542 EINA_LIST_FOREACH(elm_box_children_get(row), l, old_icon) { 543 evas_object_unref(old_icon); 544 evas_object_del(old_icon); 545 } 546 547 if (icon) { 548 /* Workaround for icon display bug: 549 * http://trac.enlightenment.org/e/ticket/1616 */ 550 evas_object_size_hint_min_set(icon, 16, 16); 551 evas_object_image_filled_set(icon, EINA_FALSE); 552 evas_object_image_fill_set(icon, 16, 0, 16, 16); 553 // elm_object_part_content_set(app_data->url_bar, "icon", icon); 554 elm_box_pack_end(row, icon); 555 evas_object_ref(icon); 556 evas_object_show(icon); 557 } 558 } 559 560 void 561 make_favicon(Evas_Object *icon, Buffer_Data *bd) 562 { 563 Ewk_Favicon_Database *database; 564 Window_Data *wd = bd->window; 565 Evas *e = evas_object_evas_get(bd->view); 566 const char *url = ewk_view_url_get(bd->view); 567 568 // elm_box_clear(icon); 569 database = ewk_context_favicon_database_get(ewk_context_default_get()); 570 ewk_favicon_database_async_icon_get( 571 database, 572 url, 573 e, 574 received_favicon_cb, 575 icon); 576 } 577 578 void 579 make_url(Evas_Object *label, Buffer_Data *bd) 580 { 581 const char *url = ewk_view_url_get(bd->view); 582 583 if (strncmp(url, "http://", 7) == 0) 584 url += 7; 585 else if (strncmp(url, "https://", 8) == 0) 586 url += 8; 587 if (strncmp(url, "file://", 7) == 0) 588 url += 7; 589 590 /* 591 if (!strncmp(uri, "https://", 8)) { 592 Evas_Object *frame = ewk_view_frame_main_get(bd->view); 593 Ewk_Certificate_Status cert_status = ewk_frame_certificate_status_get(frame); 594 if (cert_status & EWK_CERTIFICATE_STATUS_TRUSTED) 595 url_color = "#6F6"; 596 else if (cert_status & EWK_CERTIFICATE_STATUS_UNTRUSTED) 597 url_color = "#F66"; 598 599 uri += 8; 600 } 601 else 602 uri += 7; 603 */ 604 605 elm_object_text_set(label, url); 606 evas_object_show(label); 607 } 608 609 void 610 make_bf_list(Evas_Object *label, Buffer_Data *bd) 611 { 612 Eina_Bool back, fwd; 613 Eina_Strbuf *buf; 614 615 buf = eina_strbuf_new(); 616 back = ewk_view_back_possible(bd->view); 617 fwd = ewk_view_forward_possible(bd->view); 618 619 if (back || fwd) 620 eina_strbuf_append_printf(buf, "[%s%s]", back ? "+" : "", fwd ? "-" : ""); 621 622 elm_object_text_set(label, eina_strbuf_string_steal(buf)); 623 } 624 625 const char* 626 uri_sanitize(const char *uri) 627 { 628 char *tmp, *spaces; 629 int len; 630 Eina_Strbuf *buf = eina_strbuf_new(); 631 632 printf("uri_sanitize() url = \"%s\"\n", uri); 633 634 if (!uri || !*uri) return NULL; 635 636 /* TODO: strip whitespace, different search engines */ 637 len = strlen(uri); 638 tmp = strstr(uri, "://"); 639 spaces = strchr(uri, ' '); 640 641 if (len > 3 && tmp) 642 eina_strbuf_append(buf, uri); 643 else if (ecore_file_exists(uri)) 644 eina_strbuf_append_printf(buf, "file://%s", ecore_file_realpath(uri)); 645 else if (spaces || !strchr(uri, '.')) 646 eina_strbuf_append_printf(buf, "https://duckduckgo.com/html/?q=%s", uri); 647 else 648 eina_strbuf_append_printf(buf, "http://%s", uri); 649 650 return eina_strbuf_string_steal(buf); 651 } 652