NetSurf
download.c
Go to the documentation of this file.
1/*
2 * Copyright 2008-2010 Chris Young <chris@unsatisfactorysoftware.co.uk>
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#include <string.h>
20
21#include <proto/wb.h>
22#include <proto/asl.h>
23#include <proto/exec.h>
24#include <proto/dos.h>
25#include <proto/intuition.h>
26#include <proto/utility.h>
27#include <proto/icon.h>
28#ifdef __amigaos4__
29#include <proto/application.h>
30#endif
31
32#include <workbench/icon.h>
33
34#include <proto/window.h>
35#include <proto/layout.h>
36
37#include <proto/fuelgauge.h>
38#include <classes/window.h>
39#include <gadgets/fuelgauge.h>
40#include <gadgets/layout.h>
41
42#include <reaction/reaction_macros.h>
43
44#include "utils/errors.h"
45#include "utils/nsurl.h"
46#include "utils/log.h"
47#include "utils/messages.h"
48#include "utils/utils.h"
49#include "utils/nsoption.h"
50#include "utils/string.h"
52#include "netsurf/mouse.h"
53#include "netsurf/window.h"
54#include "netsurf/download.h"
56#include "desktop/download.h"
58
59#include "amiga/gui.h"
60#include "amiga/download.h"
61#include "amiga/object.h"
62#include "amiga/bitmap.h"
63#include "amiga/icon.h"
64#include "amiga/file.h"
65#include "amiga/iff_dr2d.h"
66#include "amiga/libs.h"
67#include "amiga/misc.h"
68#include "amiga/theme.h"
69#include "amiga/utf8.h"
70
71#ifndef APPNOTIFY_DisplayTime
72#define APPNOTIFY_DisplayTime ( TAG_USER + 13 )
73#endif
74
75#ifndef APPNOTIFY_Percentage
76#define APPNOTIFY_Percentage ( TAG_USER + 14 )
77#endif
78
79#ifndef APPNOTIFY_StopBackMsg
80#define APPNOTIFY_StopBackMsg ( TAG_USER + 17 )
81#endif
82
83enum {
89};
90
93 struct Window *win;
95 BPTR fh;
99 struct dlnode *dln;
102 const char *url;
103 char fname[1024];
105};
106
107enum {
112};
113
114static void ami_download_window_abort(void *w);
115static BOOL ami_download_window_event(void *w);
116
120};
121
123
125 struct gui_window *gui)
126{
129 struct gui_download_window *dw;
130 char *dl_filename = ami_utf8_easy(download_context_get_filename(ctx));
131 APTR va[3];
132
133 dw = calloc(1, sizeof(struct gui_download_window));
134
135 if(gui && (!IsListEmpty(ami_gui_get_download_list(gui)) &&
136 (dw->dln = (struct dlnode *)FindName(ami_gui_get_download_list(gui), url)))) {
137 strcpy(dw->fname, dw->dln->filename);
138 free(dw->dln->node.ln_Name);
139 dw->dln->node.ln_Name = NULL;
140 }
141 else
142 {
143 if(AslRequestTags(savereq,
144 ASLFR_Window, ami_gui_get_window(gui),
145 ASLFR_SleepWindow, TRUE,
146 ASLFR_TitleText, messages_get("NetSurf"),
147 ASLFR_Screen, ami_gui_get_screen(),
148 ASLFR_InitialFile, dl_filename,
149 TAG_DONE))
150 {
151 strlcpy(dw->fname, savereq->fr_Drawer, 1024);
152 AddPart((STRPTR)&dw->fname,savereq->fr_File,1024);
154 {
155 free(dw);
156 return NULL;
157 }
158 }
159 else
160 {
161 free(dw);
162 return NULL;
163 }
164 }
165
166 if(dl_filename) ami_utf8_free(dl_filename);
167 dw->size = total_size;
168 dw->downloaded = 0;
169 if(gui) dw->bw = ami_gui_get_browser_window(gui);
170 dw->url = url;
171
172 va[0] = (APTR)dw->downloaded;
173 va[1] = (APTR)dw->size;
174 va[2] = 0;
175
176 if(!(dw->fh = FOpen((STRPTR)&dw->fname,MODE_NEWFILE,0)))
177 {
178 free(dw);
179 return NULL;
180 }
181
182 if((nsoption_bool(download_notify_progress) == true)) {
183 char bkm[1030];
184 snprintf(bkm, 1030, "STOP %p", dw);
185
186 Notify(ami_gui_get_app_id(), APPNOTIFY_Title, messages_get("amiDownloading"),
187 APPNOTIFY_PubScreenName, "FRONT",
188 APPNOTIFY_Text, dw->fname,
192 TAG_DONE);
193 } else {
195 WA_ScreenTitle, ami_gui_get_screen_title(),
196 WA_Title, dw->url,
197 WA_Activate, TRUE,
198 WA_DepthGadget, TRUE,
199 WA_DragBar, TRUE,
200 WA_CloseGadget, FALSE,
201 WA_SizeGadget, TRUE,
202 WA_PubScreen, ami_gui_get_screen(),
203 WINDOW_SharedPort, ami_gui_get_shared_msgport(),
204 WINDOW_UserData,dw,
205 WINDOW_IconifyGadget, FALSE,
206 WINDOW_LockHeight,TRUE,
207 WINDOW_Position, WPOS_CENTERSCREEN,
208 WINDOW_ParentGroup, dw->objects[GID_D_MAIN] = LayoutVObj,
209 LAYOUT_AddChild, dw->objects[GID_D_STATUS] = FuelGaugeObj,
210 GA_ID,GID_D_STATUS,
211 GA_Text,messages_get("amiDownload"),
212 FUELGAUGE_Min,0,
213 FUELGAUGE_Max,total_size,
214 FUELGAUGE_Level,0,
215 FUELGAUGE_Ticks,11,
216 FUELGAUGE_ShortTicks,TRUE,
217 FUELGAUGE_VarArgs,va,
218 FUELGAUGE_Percent,FALSE,
219 FUELGAUGE_Justification,FGJ_CENTER,
220 FuelGaugeEnd,
221 CHILD_NominalSize,TRUE,
222 CHILD_WeightedHeight,0,
223 LAYOUT_AddChild, dw->objects[GID_D_CANCEL] = ButtonObj,
224 GA_ID,GID_D_CANCEL,
225 GA_RelVerify,TRUE,
226 GA_Text,messages_get("Abort"),
227 GA_TabCycle,TRUE,
228 ButtonEnd,
229 EndGroup,
230 EndWindow;
231
232 dw->win = (struct Window *)RA_OpenWindow(dw->objects[OID_D_MAIN]);
233 }
234
235 dw->ctx = ctx;
237
239
241
242 return dw;
243}
244
246 const char *data, unsigned int size)
247{
248 APTR va[3];
249 if(!dw) return NSERROR_SAVE_FAILED;
250
251 FWrite(dw->fh,data,1,size);
252
253 dw->downloaded = dw->downloaded + size;
254
255 va[0] = (APTR)dw->downloaded;
256 va[1] = (APTR)dw->size;
257 va[2] = 0;
258
259 if(dw->size) {
260 if((nsoption_bool(download_notify_progress) == true) &&
261 (((dw->downloaded * 100) / dw->size) > dw->progress)) {
262 dw->progress = (uint32)((dw->downloaded * 100) / dw->size);
265 TAG_DONE);
266 } else {
267 RefreshSetGadgetAttrs((struct Gadget *)dw->objects[GID_D_STATUS], dw->win, NULL,
268 FUELGAUGE_Level, dw->downloaded,
269 GA_Text, messages_get("amiDownload"),
270 FUELGAUGE_VarArgs, va,
271 TAG_DONE);
272 }
273 }
274 else
275 {
276 if((nsoption_bool(download_notify_progress) == true)) {
277 /* unknown size, not entirely sure how to deal with this atm... */
280 TAG_DONE);
281 } else {
282 RefreshSetGadgetAttrs((struct Gadget *)dw->objects[GID_D_STATUS], dw->win, NULL,
283 FUELGAUGE_Level, dw->downloaded,
284 GA_Text, messages_get("amiDownloadU"),
285 FUELGAUGE_VarArgs, va,
286 TAG_DONE);
287 }
288 }
289
290 return NSERROR_OK;
291}
292
294{
295 struct dlnode *dln,*dln2 = NULL;
296 struct browser_window *bw;
297 bool queuedl = false;
298
299 if(!dw) return;
300 bw = dw->bw;
301
304
305 if((nsoption_bool(download_notify_progress) == true)) {
307 APPNOTIFY_Update, TRUE,
308 TAG_DONE);
309 }
310
311 if((nsoption_bool(download_notify)) && (dw->result == AMINS_DLOAD_OK))
312 {
313 char bkm[1030];
314 snprintf(bkm, 1030, "OPEN %s", dw->fname);
315
316 Notify(ami_gui_get_app_id(), APPNOTIFY_Title, messages_get("amiDownloadComplete"),
317 APPNOTIFY_PubScreenName, "FRONT",
318 APPNOTIFY_BackMsg, bkm,
319 APPNOTIFY_CloseOnDC, TRUE,
320 APPNOTIFY_Text, dw->fname,
321 TAG_DONE);
322 }
323
325
326 if((dln = dw->dln))
327 {
328 dln2 = (struct dlnode *)GetSucc((struct Node *)dln);
329 if((dln!=dln2) && (dln2)) queuedl = true;
330
331 free(dln->filename);
332 Remove((struct Node *)dln);
333 free(dln);
334 }
335
336 FClose(dw->fh);
337 SetComment(dw->fname, dw->url);
338
340
341 if(dw->objects[OID_D_MAIN] != NULL) {
342 DisposeObject(dw->objects[OID_D_MAIN]);
343 }
344
346 if(queuedl) {
347 nsurl *url;
348 if (nsurl_create(dln2->node.ln_Name, &url) != NSERROR_OK) {
349 amiga_warn_user("NoMemory", 0);
350 } else {
352 url,
353 NULL,
355 NULL,
356 NULL,
357 NULL);
358 nsurl_unref(url);
359 }
360 }
361 ami_try_quit(); /* In case the only window open was this download */
362}
363
365 const char *error_msg)
366{
367 amiga_warn_user("Unwritten","");
370}
371
372static void ami_download_window_abort(void *w)
373{
374 struct gui_download_window *dw = (struct gui_download_window *)w;
378}
379
380static BOOL ami_download_window_event(void *w)
381{
382 /* return TRUE if window destroyed */
383 struct gui_download_window *dw = (struct gui_download_window *)w;
384 ULONG result;
385 uint16 code;
386
387 if(dw == NULL) return FALSE; /* We may not have a real window */
388
389 while((result = RA_HandleInput(dw->objects[OID_D_MAIN], &code)) != WMHI_LASTMSG)
390 {
391 switch(result & WMHI_CLASSMASK) // class
392 {
393 case WMHI_GADGETUP:
394 switch(result & WMHI_GADGETMASK)
395 {
396 case GID_D_CANCEL:
398 return TRUE;
399 break;
400 }
401 break;
402 }
403 }
404 return FALSE;
405}
406
407void ami_free_download_list(struct List *dllist)
408{
409 struct dlnode *node;
410 struct dlnode *nnode;
411
412 if(!dllist) return;
413 if(IsListEmpty(dllist)) return;
414
415 node = (struct dlnode *)GetHead((struct List *)dllist);
416
417 do
418 {
419 nnode=(struct dlnode *)GetSucc((struct Node *)node);
420 free(node->node.ln_Name);
421 free(node->filename);
422 Remove((struct Node *)node);
423 free((struct Node *)node);
424 }while((node=nnode));
425}
426
428gui_window_save_link(struct gui_window *g, nsurl *url, const char *title)
429{
430 char fname[1024];
431 STRPTR openurlstring,linkname;
432 struct DiskObject *dobj = NULL;
433
434 linkname = ASPrintf("Link_to_%s",FilePart(nsurl_access(url)));
435
436 if(AslRequestTags(savereq,
437 ASLFR_Window, ami_gui_get_window(g),
438 ASLFR_SleepWindow, TRUE,
439 ASLFR_TitleText,messages_get("NetSurf"),
440 ASLFR_Screen, ami_gui_get_screen(),
441 ASLFR_InitialFile, linkname,
442 TAG_DONE))
443 {
444 strlcpy(fname, savereq->fr_Drawer, 1024);
445 AddPart(fname,savereq->fr_File,1024);
446
448
450 {
451 BPTR fh;
452
453 if((fh = FOpen(fname,MODE_NEWFILE,0)))
454 {
455 /* \todo Should be URLOpen on OS4.1 */
456 openurlstring = ASPrintf("openurl \"%s\"\n",nsurl_access(url));
457 FWrite(fh,openurlstring,1,strlen(openurlstring));
458 FClose(fh);
459 FreeVec(openurlstring);
460 SetComment(fname, nsurl_access(url));
461
462 dobj = GetIconTags(NULL,ICONGETA_GetDefaultName,"url",
463 ICONGETA_GetDefaultType,WBPROJECT,
464 TAG_DONE);
465
466 dobj->do_DefaultTool = "IconX";
467
468 PutIconTags(fname,dobj,
469 ICONPUTA_NotifyWorkbench,TRUE,
470 TAG_DONE);
471
472 FreeDiskObject(dobj);
473 }
474 FreeVec(linkname);
475 }
477 }
478 return NSERROR_OK;
479}
480
481BOOL ami_download_check_overwrite(const char *file, struct Window *win, ULONG size)
482{
483 /* Return TRUE if file can be (over-)written */
484 int32 res = 0;
485 BPTR lock = 0;
486 char *overwritetext;
487
488 if(nsoption_bool(ask_overwrite) == false) return TRUE;
489
490 lock = Lock(file, ACCESS_READ);
491
492 if(lock)
493 {
494 if(size) {
495 BPTR fh;
496 int64 oldsize = 0;
497
498 if((fh = OpenFromLock(lock))) {
499 oldsize = GetFileSize(fh);
500 Close(fh);
501 }
502 overwritetext = ASPrintf("%s\n\n%s %s\n%s %s",
503 messages_get("OverwriteFile"),
504 messages_get("amiSizeExisting"), human_friendly_bytesize((ULONG)oldsize),
505 messages_get("amiSizeNew"), human_friendly_bytesize(size));
506 } else {
507 UnLock(lock);
508 overwritetext = ASPrintf(messages_get("OverwriteFile"));
509 }
510
511 res = amiga_warn_user_multi(overwritetext, "Replace", "DontReplace", win);
512 FreeVec(overwritetext);
513 }
514 else return TRUE;
515
516 if(res == 1) return TRUE;
517 else return FALSE;
518}
519
520void ami_download_parse_backmsg(const char *backmsg)
521{
522 if((backmsg[0] == 'O') && (backmsg[1] == 'P') && (backmsg[2] == 'E') && (backmsg[3] == 'N')) {
523 OpenWorkbenchObjectA((backmsg + 5), NULL);
524 }
525}
526
532};
533
void ami_try_quit(void)
Definition: gui.c:3894
struct Window * ami_gui_get_window(struct gui_window *gw)
Get window from gui_window.
Definition: gui.c:576
struct Screen * ami_gui_get_screen(void)
Get a pointer to the screen NetSurf is running on.
Definition: gui.c:403
nserror ami_gui_win_list_add(void *win, int type, const struct ami_win_event_table *table)
Add a window to the NetSurf window list (to enable event processing)
Definition: gui.c:4668
uint32 ami_gui_get_app_id(void)
Get the application.library ID NetSurf is registered as.
Definition: gui.c:6349
void ami_set_pointer(struct gui_window_2 *gwin, gui_pointer_shape shape, bool update)
Definition: gui.c:688
void ami_reset_pointer(struct gui_window_2 *gwin)
Definition: gui.c:696
STRPTR ami_gui_get_screen_title(void)
Get the string for NetSurf's screen titlebar.
Definition: gui.c:974
struct List * ami_gui_get_download_list(struct gui_window *gw)
Get download list from gui_window.
Definition: gui.c:431
void ami_gui_win_list_remove(void *win)
Remove a window from the NetSurf window list.
Definition: gui.c:4682
struct browser_window * ami_gui_get_browser_window(struct gui_window *gw)
Get browser window from gui_window.
Definition: gui.c:419
struct gui_window_2 * ami_gui_get_gui_window_2(struct gui_window *gw)
Get gui_window_2 from gui_window.
Definition: gui.c:437
struct MsgPort * ami_gui_get_shared_msgport(void)
Get shared message port.
int32 amiga_warn_user_multi(const char *body, const char *opt1, const char *opt2, struct Window *win)
Definition: misc.c:93
nserror amiga_warn_user(const char *warning, const char *detail)
Warn the user of an event.
Definition: misc.c:79
STATIC char result[100]
Definition: arexx.c:77
Browser window creation and manipulation interface.
nserror browser_window_navigate(struct browser_window *bw, struct nsurl *url, struct nsurl *referrer, enum browser_window_nav_flags flags, char *post_urlenc, struct fetch_multipart_data *post_multipart, struct hlcache_handle *parent)
Start fetching a page in a browser window.
@ BW_NAVIGATE_DOWNLOAD
download rather than render the uri
void download_context_destroy(download_context *ctx)
Destroy a download context.
Definition: download.c:270
nsurl * download_context_get_url(const download_context *ctx)
Retrieve the URL for a download.
Definition: download.c:291
const char * download_context_get_filename(const download_context *ctx)
Retrieve the filename for a download.
Definition: download.c:310
void download_context_abort(download_context *ctx)
Abort a download fetch.
Definition: download.c:285
unsigned long long int download_context_get_total_length(const download_context *ctx)
Retrieve total byte length of download.
Definition: download.c:304
Core download context (interface)
Error codes.
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_SAVE_FAILED
Failed to save data.
Definition: errors.h:36
@ NSERROR_OK
No error.
Definition: errors.h:30
static struct gui_download_table download_table
Definition: download.c:527
static const struct ami_win_event_table ami_download_table
Definition: download.c:117
static nserror gui_download_window_data(struct gui_download_window *dw, const char *data, unsigned int size)
Definition: download.c:245
static struct gui_download_window * gui_download_window_create(download_context *ctx, struct gui_window *gui)
Definition: download.c:124
@ GID_D_CANCEL
Definition: download.c:87
@ OID_D_MAIN
Definition: download.c:84
@ GID_D_LAST
Definition: download.c:88
@ GID_D_MAIN
Definition: download.c:85
@ GID_D_STATUS
Definition: download.c:86
@ AMINS_DLOAD_ERROR
Definition: download.c:110
@ AMINS_DLOAD_ABORT
Definition: download.c:111
@ AMINS_DLOAD_OK
Definition: download.c:109
@ AMINS_DLOAD_PROGRESS
Definition: download.c:108
static BOOL ami_download_window_event(void *w)
Definition: download.c:380
void ami_free_download_list(struct List *dllist)
Definition: download.c:407
BOOL ami_download_check_overwrite(const char *file, struct Window *win, ULONG size)
Definition: download.c:481
nserror gui_window_save_link(struct gui_window *g, nsurl *url, const char *title)
Definition: download.c:428
static void gui_download_window_error(struct gui_download_window *dw, const char *error_msg)
Definition: download.c:364
#define APPNOTIFY_Percentage
Definition: download.c:76
static void gui_download_window_done(struct gui_download_window *dw)
Definition: download.c:293
struct gui_download_table * amiga_download_table
Definition: download.c:534
static int downloads_in_progress
Definition: download.c:122
static void ami_download_window_abort(void *w)
Definition: download.c:372
void ami_download_parse_backmsg(const char *backmsg)
Definition: download.c:520
#define APPNOTIFY_DisplayTime
Definition: download.c:72
#define APPNOTIFY_StopBackMsg
Definition: download.c:80
struct FileRequester * savereq
Definition: file.c:53
@ AMINS_DLWINDOW
Definition: object.h:29
void ami_utf8_free(char *ptr)
Definition: utf8.c:104
char * ami_utf8_easy(const char *string)
Definition: utf8.c:109
Content for image/ico (interface).
Content for image/x-amiga-icon (icon.library interface).
Interface to platform-specific download operations.
Core mouse and pointer states.
@ GUI_POINTER_WAIT
Definition: mouse.h:104
Interface to platform-specific graphical user interface window operations.
#define FuelGaugeObj
Definition: libs.h:58
#define WindowObj
Definition: libs.h:77
#define LayoutVObj
Definition: libs.h:65
#define ButtonObj
Definition: libs.h:54
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
Localised message support (interface).
NetSurf URL handling (interface).
nserror nsurl_create(const char *const url_s, nsurl **url)
Create a NetSurf URL object from a URL string.
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
char * ASPrintf(const char *fmt,...)
Definition: os3support.c:139
int64 GetFileSize(BPTR fh)
Definition: os3support.c:337
struct Node * GetHead(struct List *list)
Definition: os3support.c:364
ULONG RefreshSetGadgetAttrs(struct Gadget *g, struct Window *w, struct Requester *r, Tag tag1,...)
Definition: os3support.c:429
struct Node * GetSucc(struct Node *node)
Definition: os3support.c:381
#define Notify(...)
Definition: os3support.h:143
int64_t int64
Definition: os3support.h:185
#define FOpen(A, B, C)
Definition: os3support.h:158
int32_t int32
Definition: os3support.h:183
uint16_t uint16
Definition: os3support.h:182
uint32_t uint32
Definition: os3support.h:184
#define FClose(A)
Definition: os3support.h:159
Save HTML document with dependencies (interface).
Interface to utility string handling.
char * human_friendly_bytesize(unsigned long long int bytesize)
Create a human readable representation of a size in bytes.
Definition: utils.c:209
Browser window data.
struct browser_window * bw
struct Node node
Definition: download.h:33
char * filename
Definition: download.h:34
A context for a download.
Definition: download.c:40
function table for download windows.
Definition: download.h:34
struct gui_download_window *(* create)(struct download_context *ctx, struct gui_window *parent)
Definition: download.h:35
context for each download.
Definition: download.c:91
struct ami_generic_window w
Definition: download.c:92
unsigned int total_size
Size of resource, or 0 if unknown.
Definition: download.c:92
const char * url
Definition: download.c:102
struct browser_window * bw
Definition: download.c:100
struct download_context * ctx
Associated context, or 0 if the fetch has completed or aborted.
Definition: download.c:101
Object * objects[GID_D_LAST]
Definition: download.c:94
char fname[1024]
Definition: download.c:103
struct Window * win
Definition: download.c:93
struct dlnode * dln
Definition: download.c:99
first entry in window list
Definition: gui.c:296
Option reading and saving interface.
#define nsoption_bool(OPTION)
Get the value of a boolean option.
Definition: nsoption.h:270
Interface to a number of general purpose functionality.