viking

webkit based web browser for Enlightenment
Log | Files | Refs | LICENSE

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