NetSurf
cookies.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2015 Adrián Arroyo Calle <adrian.arroyocalle@gmail.com>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#define __STDBOOL_H__ 1
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23extern "C" {
24#include "utils/log.h"
25#include "netsurf/mouse.h"
26#include "netsurf/plotters.h"
27#include "netsurf/cookie_db.h"
28#include "netsurf/keypress.h"
30}
31#include "beos/cookies.h"
32
33#include <Application.h>
34#include <InterfaceKit.h>
35#include <String.h>
36#include <Button.h>
37#include <Catalog.h>
38#include <private/interface/ColumnListView.h>
39#include <private/interface/ColumnTypes.h>
40#include <GroupLayoutBuilder.h>
41#include <NetworkCookieJar.h>
42#include <OutlineListView.h>
43#include <ScrollView.h>
44#include <StringView.h>
45
46#include <vector>
47
48static std::vector<struct cookie_data*> cookieJar;
49
50class CookieWindow : public BWindow {
51public:
52 CookieWindow(BRect frame);
53 virtual void MessageReceived(BMessage* message);
54 virtual void Show();
55 virtual bool QuitRequested();
56
57private:
58 void _BuildDomainList();
59 BStringItem* _AddDomain(BString domain, bool fake);
60 void _ShowCookiesForDomain(BString domain);
61 void _DeleteCookies();
62
63private:
64 BOutlineListView* fDomains;
65 BColumnListView* fCookies;
66 BStringView* fHeaderView;
67};
68
69enum {
70 COOKIE_IMPORT = 'cimp',
71 COOKIE_EXPORT = 'cexp',
72 COOKIE_DELETE = 'cdel',
74
75 DOMAIN_SELECTED = 'dmsl'
76};
77
78
79class CookieDateColumn: public BDateColumn
80{
81public:
82 CookieDateColumn(const char* title, float width)
83 :
84 BDateColumn(title, width, width / 2, width * 2)
85 {
86 }
87
88 void DrawField(BField* field, BRect rect, BView* parent) {
89 BDateField* dateField = (BDateField*)field;
90 if (dateField->UnixTime() == -1) {
91 DrawString("Session cookie", parent, rect);
92 } else {
93 BDateColumn::DrawField(field, rect, parent);
94 }
95 }
96};
97
98
99class CookieRow: public BRow
100{
101public:
102 CookieRow(BColumnListView* list, struct cookie_data& cookie)
103 :
104 BRow(),
105 fCookie(cookie)
106 {
107 list->AddRow(this);
108 SetField(new BStringField(cookie.name), 0);
109 SetField(new BStringField(cookie.path), 1);
110 time_t expiration = cookie.expires;
111 SetField(new BDateField(&expiration), 2);
112 SetField(new BStringField(cookie.value), 3);
113
114 BString flags;
115 if (cookie.secure)
116 flags = "https ";
117 if (cookie.http_only)
118 flags = "http ";
119
120 SetField(new BStringField(flags.String()), 4);
121 }
122
123public:
125};
126
127
128class DomainItem: public BStringItem
129{
130public:
131 DomainItem(BString text, bool empty)
132 :
133 BStringItem(text),
135 {
136 }
137
138public:
139 bool fEmpty;
140};
141
142
144 :
145 BWindow(frame,"Cookie manager", B_TITLED_WINDOW,
146 B_NORMAL_WINDOW_FEEL,
147 B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS)
148{
149 BGroupLayout* root = new BGroupLayout(B_HORIZONTAL, 0.0);
150 SetLayout(root);
151
152 fDomains = new BOutlineListView("domain list");
153 root->AddView(new BScrollView("scroll", fDomains, 0, false, true), 1);
154
155 fHeaderView = new BStringView("label","The cookie jar is empty!");
156 fCookies = new BColumnListView("cookie list", B_WILL_DRAW, B_FANCY_BORDER,
157 false);
158
159 float em = fCookies->StringWidth("M");
160 float flagsLength = fCookies->StringWidth("Mhttps hostOnly" B_UTF8_ELLIPSIS);
161
162 fCookies->AddColumn(new BStringColumn("Name",
163 20 * em, 10 * em, 50 * em, 0), 0);
164 fCookies->AddColumn(new BStringColumn("Path",
165 10 * em, 10 * em, 50 * em, 0), 1);
166 fCookies->AddColumn(new CookieDateColumn("Expiration",
167 fCookies->StringWidth("88/88/8888 88:88:88 AM")), 2);
168 fCookies->AddColumn(new BStringColumn("Value",
169 20 * em, 10 * em, 50 * em, 0), 3);
170 fCookies->AddColumn(new BStringColumn("Flags",
171 flagsLength, flagsLength, flagsLength, 0), 4);
172
173 root->AddItem(BGroupLayoutBuilder(B_VERTICAL, B_USE_DEFAULT_SPACING)
174 .SetInsets(5, 5, 5, 5)
175 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
176 .Add(fHeaderView)
177 .AddGlue()
178 .End()
179 .Add(fCookies)
180 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
181 .SetInsets(5, 5, 5, 5)
182 .AddGlue()
183 .Add(new BButton("delete", "Delete",
184 new BMessage(COOKIE_DELETE))), 3);
185
186 fDomains->SetSelectionMessage(new BMessage(DOMAIN_SELECTED));
187}
188
189
190void
192{
193 switch(message->what) {
194 case DOMAIN_SELECTED:
195 {
196 int32 index = message->FindInt32("index");
197 BStringItem* item = (BStringItem*)fDomains->ItemAt(index);
198 if (item != NULL) {
199 BString domain = item->Text();
200 _ShowCookiesForDomain(domain);
201 }
202 return;
203 }
204
205 case COOKIE_REFRESH:
207 return;
208
209 case COOKIE_DELETE:
211 return;
212 }
213 BWindow::MessageReceived(message);
214}
215
216
217void
219{
220 BWindow::Show();
221 if (IsHidden())
222 return;
223
224 PostMessage(COOKIE_REFRESH);
225}
226
227
228bool
230{
231 if (!IsHidden())
232 Hide();
233 cookieJar.clear();
234 return false;
235}
236
237
238void
240{
241 // Empty the domain list (TODO should we do this when hiding instead?)
242 for (int i = fDomains->FullListCountItems() - 1; i >= 1; i--) {
243 delete fDomains->FullListItemAt(i);
244 }
245 fDomains->MakeEmpty();
246
247 // BOutlineListView does not handle parent = NULL in many methods, so let's
248 // make sure everything always has a parent.
249 DomainItem* rootItem = new DomainItem("", true);
250 fDomains->AddItem(rootItem);
251
252 // Populate the domain list - TODO USE STL VECTOR
253
254
255 for(std::vector<struct cookie_data*>::iterator it = cookieJar.begin(); it != cookieJar.end(); ++it) {
256 _AddDomain((*it)->domain, false);
257 }
258
259 int i = 1;
260 while (i < fDomains->FullListCountItems())
261 {
262 DomainItem* item = (DomainItem*)fDomains->FullListItemAt(i);
263 // Detach items from the fake root
264 item->SetOutlineLevel(item->OutlineLevel() - 1);
265 i++;
266 }
267 fDomains->RemoveItem(rootItem);
268 delete rootItem;
269
270 i = 0;
271 int firstNotEmpty = i;
272 // Collapse empty items to keep the list short
273 while (i < fDomains->FullListCountItems())
274 {
275 DomainItem* item = (DomainItem*)fDomains->FullListItemAt(i);
276 if (item->fEmpty == true) {
277 if (fDomains->CountItemsUnder(item, true) == 1) {
278 // The item has no cookies, and only a single child. We can
279 // remove it and move its child one level up in the tree.
280
281 int count = fDomains->CountItemsUnder(item, false);
282 int index = fDomains->FullListIndexOf(item) + 1;
283 for (int j = 0; j < count; j++) {
284 BListItem* child = fDomains->FullListItemAt(index + j);
285 child->SetOutlineLevel(child->OutlineLevel() - 1);
286 }
287
288 fDomains->RemoveItem(item);
289 delete item;
290
291 // The moved child is at the same index the removed item was.
292 // We continue the loop without incrementing i to process it.
293 continue;
294 } else {
295 // The item has no cookies, but has multiple children. Mark it
296 // as disabled so it is not selectable.
297 item->SetEnabled(false);
298 if (i == firstNotEmpty)
299 firstNotEmpty++;
300 }
301 }
302
303 i++;
304 }
305
306 fDomains->Select(firstNotEmpty);
307}
308
309
310BStringItem*
311CookieWindow::_AddDomain(BString domain, bool fake)
312{
313 BStringItem* parent = NULL;
314 int firstDot = domain.FindFirst('.');
315 if (firstDot >= 0) {
316 BString parentDomain(domain);
317 parentDomain.Remove(0, firstDot + 1);
318 parent = _AddDomain(parentDomain, true);
319 } else {
320 parent = (BStringItem*)fDomains->FullListItemAt(0);
321 }
322
323 BListItem* existing;
324 int i = 0;
325 // check that we aren't already there
326 while ((existing = fDomains->ItemUnderAt(parent, true, i++)) != NULL) {
327 DomainItem* stringItem = (DomainItem*)existing;
328 if (stringItem->Text() == domain) {
329 if (fake == false)
330 stringItem->fEmpty = false;
331 return stringItem;
332 }
333 }
334
335 // Insert the new item, keeping the list alphabetically sorted
336 BStringItem* domainItem = new DomainItem(domain, fake);
337 domainItem->SetOutlineLevel(parent->OutlineLevel() + 1);
338 BStringItem* sibling = NULL;
339 int siblingCount = fDomains->CountItemsUnder(parent, true);
340 for (i = 0; i < siblingCount; i++) {
341 sibling = (BStringItem*)fDomains->ItemUnderAt(parent, true, i);
342 if (strcmp(sibling->Text(), domainItem->Text()) > 0) {
343 fDomains->AddItem(domainItem, fDomains->FullListIndexOf(sibling));
344 return domainItem;
345 }
346 }
347
348 if (sibling) {
349 // There were siblings, but all smaller than what we try to insert.
350 // Insert after the last one (and its subitems)
351 fDomains->AddItem(domainItem, fDomains->FullListIndexOf(sibling)
352 + fDomains->CountItemsUnder(sibling, false) + 1);
353 } else {
354 // There were no siblings, insert right after the parent
355 fDomains->AddItem(domainItem, fDomains->FullListIndexOf(parent) + 1);
356 }
357
358 return domainItem;
359}
360
361
362void
364{
365 BString label;
366 label.SetToFormat("Cookies for %s", domain.String());
367 fHeaderView->SetText(label);
368
369 // Empty the cookie list
370 fCookies->Clear();
371
372 // Populate the domain list
373
374 for(std::vector<struct cookie_data*>::iterator it = cookieJar.begin(); it != cookieJar.end(); ++it) {
375 if((*it)->domain == domain) {
376 new CookieRow(fCookies,**it);
377 }
378 }
379}
380
381static bool nsbeos_cookie_parser(const struct cookie_data* data)
382{
383 cookieJar.push_back((struct cookie_data*)data);
384 return true;
385}
386
387void
389{
390 // TODO shall we handle multiple selection here?
391 CookieRow* row = (CookieRow*)fCookies->CurrentSelection();
392 if (row == NULL) {
393 // TODO see if a domain is selected in the domain list, and delete all
394 // cookies for that domain
395 return;
396 }
397
398 fCookies->RemoveRow(row);
399
401 cookieJar.clear();
403
404 delete row;
405}
406
407/**
408 * Creates the Cookie Manager
409 */
411{
412 CookieWindow* cookWin=new CookieWindow(BRect(100,100,700,500));
413 cookWin->Show();
414 cookWin->Activate();
416}
static uint32_t count(const http_directive *list, lwc_string *key)
CookieDateColumn(const char *title, float width)
Definition: cookies.cpp:82
void DrawField(BField *field, BRect rect, BView *parent)
Definition: cookies.cpp:88
CookieRow(BColumnListView *list, struct cookie_data &cookie)
Definition: cookies.cpp:102
struct cookie_data fCookie
Definition: cookies.cpp:124
void _ShowCookiesForDomain(BString domain)
Definition: cookies.cpp:363
virtual void MessageReceived(BMessage *message)
Definition: cookies.cpp:191
CookieWindow(BRect frame)
Definition: cookies.cpp:143
BOutlineListView * fDomains
Definition: cookies.cpp:64
virtual bool QuitRequested()
Definition: cookies.cpp:229
void _BuildDomainList()
Definition: cookies.cpp:239
virtual void Show()
Definition: cookies.cpp:218
BStringItem * _AddDomain(BString domain, bool fake)
Definition: cookies.cpp:311
BColumnListView * fCookies
Definition: cookies.cpp:65
BStringView * fHeaderView
Definition: cookies.cpp:66
void _DeleteCookies()
Definition: cookies.cpp:388
DomainItem(BString text, bool empty)
Definition: cookies.cpp:131
bool fEmpty
Definition: cookies.cpp:139
Unified cookie database public interface.
void urldb_iterate_cookies(bool(*callback)(const struct cookie_data *cookie))
Iterate over all cookies in database.
void urldb_delete_cookie(const char *domain, const char *path, const char *name)
Delete a cookie.
Definition: urldb.c:4273
Cookie Manager (interface).
@ COOKIE_EXPORT
Definition: cookies.cpp:71
@ COOKIE_REFRESH
Definition: cookies.cpp:73
@ COOKIE_DELETE
Definition: cookies.cpp:72
@ DOMAIN_SELECTED
Definition: cookies.cpp:75
@ COOKIE_IMPORT
Definition: cookies.cpp:70
static bool nsbeos_cookie_parser(const struct cookie_data *data)
Definition: cookies.cpp:381
void nsbeos_cookies_init(void)
Creates the Cookie Manager.
Definition: cookies.cpp:410
static std::vector< struct cookie_data * > cookieJar
Definition: cookies.cpp:48
wimp_w parent
Definition: dialog.c:88
static struct directory * root
Definition: filename.c:55
Core mouse and pointer states.
Target independent plotting interface.
Interface to key press operations.
int32_t int32
Definition: os3support.h:183
int width
Definition: gui.c:159
Interface to utility string handling.
const char * name
Cookie name.
Definition: cookie_db.h:48
const bool http_only
Only expose to HTTP(S) requests.
Definition: cookie_db.h:59
const char * domain
Domain.
Definition: cookie_db.h:53
const bool secure
Only send for HTTPS requests.
Definition: cookie_db.h:58
const char * value
Cookie value.
Definition: cookie_db.h:49
const char * path
Path.
Definition: cookie_db.h:55
const time_t expires
Expiry timestamp, or 1 for session.
Definition: cookie_db.h:56
Rectangle coordinates.
Definition: types.h:40
static struct search_node empty
Definition: urldb.c:282
static nserror text(const struct redraw_context *ctx, const struct plot_font_style *fstyle, int x, int y, const char *text, size_t length)
Text plotting.
Definition: plot.c:978