summaryrefslogtreecommitdiff
path: root/surf-webext-dom.c
blob: 31e1308f50be3e944a4bf7339d54465574d91a9a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//
// !!! THIS IS A BUGGY CONCEPT/PROTOTYPE. USE AT YOUR OWN RISK !!!
//
// The following simple Webkit2GTK+ extension was hacked together
// in the sleepless night between 09th and 10th March 2018 by:
//
// Michal Idziorek <m.i@gmx.at>.
//
// It regjsters a document_loaded_callback, where the DOM is manipulated,
// i.e: a <span> with a number added to every link encountered.
//
// The urls are extracted from the DOM and shared with the browsers 
// process over a system V memory segment. 
//
// As an example, this can be used to enable keyboardless navigation 
// in surf by simply typing in the number of the link. 
//
// TODO: Support multiple clients! See source for more TODOS!
//       THE biggest limitation by now is the lazily hardcoded:
//       key_t my_ftok = ftok("~/surf-webext-dom-shared-mem",'a');
//
// Last Update: 10th March 2018
// 
// Last Tested: with surf commit 81f0452bc6c2a110239fa303ad1e72f11c33dc94
//              from htps://git.suckless.org/surf
// 

#include <webkit2/webkit-web-extension.h>

#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>

bool str_prefix(const char *str, const char *pre);

void
document_loaded_callback (WebKitWebPage *web_page,
                          GPtrArray     *elements,
                          GVariant      *user_data)
{

    // TODO: g_free where appropriate !!
    // TODO: allow focus on input boxes/forms 
    // TODO: Put this somehwere else? (but I dislike #defines)
    // share this info with surf itself! maybe surf can supply this along
    // the ftok path via the user_data GVariant.
    int MAX_LINKS=1024;
    int MAX_LINK_LENGTH=1024;
    int DEBUG=3;

    // get html doc
    WebKitDOMHTMLDocument *doc	   = webkit_web_page_get_dom_document(web_page);
    if(!WEBKIT_DOM_IS_HTML_DOCUMENT(doc))return;

    // get url
    char *url = webkit_dom_document_get_url (doc); 
    if(DEBUG>1) g_print("document_loaded (callback): %s\n", url);

    // tokenize url
    char *url_proto=strtok(url,"/");
    char *url_host=strtok(NULL,"/");
    if(DEBUG>2) g_print("proto: %s\n", url_proto);
    if(DEBUG>2) g_print("host: %s\n", url_host);

    // get html body
    WebKitDOMHTMLElement *body  = webkit_dom_document_get_body(doc);

    // get links (alt)
    /* altenative way, what is the difference (TODO)?
    WebKitDOMNodeList *links = webkit_dom_document_query_selector_all(doc,"a",NULL);
    gulong links_count		   = webkit_dom_node_list_get_length (links);
    g_print("extracted %i links\n",links_count);
    */

    // get links 
    WebKitDOMHTMLCollection *links = webkit_dom_document_get_links(doc);
    gulong links_count		   = webkit_dom_html_collection_get_length (links);
    if(DEBUG>1) g_print("extracted %i links\n",links_count);

    // attach to shared memory;
    key_t my_ftok = ftok("~/surf-webext-dom-shared-mem",'a');
    
    // TODO: should we need the size again here?
    int mem_seg=shmget(my_ftok,MAX_LINKS*MAX_LINK_LENGTH,IPC_CREAT|0660);
    if(mem_seg==-1)
    {
	g_print("shmget failed: %s\n",strerror(errno));
    }

    char *shared_buf=shmat(mem_seg,NULL,0);
    if(shared_buf==(void*)-1)
    {
	g_print("shmat failed: %s\n",strerror(errno));
    }
    
    // iterate over links
    for(gulong i=0;i<links_count;i++)
    {
	char buf[MAX_LINK_LENGTH]; // TODO: dynamic!

	WebKitDOMHTMLLinkElement * node = webkit_dom_html_collection_item (links,i);

	// add hint for keyboard navigation
	char *txt = webkit_dom_html_element_get_inner_html (node); 

	// TODO: style via stylesheet
	snprintf(buf,MAX_LINK_LENGTH, 
		"<span style='padding-right:5px;border-bottom:1px solid black;'>\
		<span style='font-size:13px;font-weight:bold;font-face:Arial;\
		      border:1px solid black;display:inline;color:white;\
		      background-color:#c0474c;padding:0 5px;margin:0;\
		      margin-right:5px;'>%i</span>%s</span>", i,txt);

	webkit_dom_html_element_set_inner_html (node,buf,NULL);

	// alternatively add hints at the end of the body
	// webkit_dom_element_insert_adjacent_html (body,"beforeend",buf,NULL);

	// TODO: this does not work for some sad reason. 
	// sadly, likely due to my misunderstanding.
	// node seems not to be a LinkElement at all :(
	// txt = webkit_dom_html_link_element_get_href (node); 
	// so we have to use this:
	txt = webkit_dom_element_get_attribute (node,"href");
	if(str_prefix(txt,"//"))     snprintf(buf,MAX_LINK_LENGTH,"%s%s",url_proto,txt);
	else if(str_prefix(txt,"/")) snprintf(buf,MAX_LINK_LENGTH,"%s//%s%s",url_proto,url_host,txt);
	else                         snprintf(buf,MAX_LINK_LENGTH,"%s",txt);
	
	if(i<MAX_LINKS) snprintf(&(shared_buf[MAX_LINK_LENGTH*i]),MAX_LINK_LENGTH,"%s\0",buf);
        if(DEBUG>10) g_print("extracted link : %s\n",buf);
    }
}

static void
page_created_callback (WebKitWebExtension *extension,
                       WebKitWebPage      *web_page,
                       GVariant           *user_data)
{
    g_signal_connect (web_page, "document-loaded", 
                      G_CALLBACK (document_loaded_callback), 
                      user_data);
}

G_MODULE_EXPORT void
webkit_web_extension_initialize_with_user_data (WebKitWebExtension *extension,
					        GVariant           *user_data)
{
    g_signal_connect (extension, "page-created", 
                      G_CALLBACK (page_created_callback),
                      user_data );
}

//https://stackoverflow.com/questions/4770985/how-to-check-if-a-string-starts-with-another-string-in-c
bool str_prefix(const char *str, const char *pre)
{
    size_t lenpre = strlen(pre),
           lenstr = strlen(str);
    return lenstr < lenpre ? false : strncmp(pre, str, lenpre) == 0;
}