NetSurf
download.c
Go to the documentation of this file.
1/*
2 * Copyright 2010 Ole Loots <ole@monochrom.net>
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 <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <string.h>
26#include <stdbool.h>
27#include <time.h>
28
29#include "utils/log.h"
30#include "utils/messages.h"
31#include "utils/nsoption.h"
32#include "utils/string.h"
33#include "netsurf/inttypes.h"
35#include "netsurf/download.h"
37#include "desktop/download.h"
38
39#include "atari/gui.h"
40#include "atari/misc.h"
41#include "atari/res/netsurf.rsh"
42#include "atari/download.h"
43#include "atari/osspec.h"
44
45extern struct gui_window * input_window;
46extern GRECT desk_area;
47
48static void gui_download_window_destroy( struct gui_download_window * gdw );
49static void on_abort_click(struct gui_download_window *dw);
50static void on_cbrdy_click(struct gui_download_window *dw);
51static void on_close(struct gui_download_window * dw);
52static void on_redraw(struct gui_download_window *dw, GRECT *clip);
53
54static void toolbar_redraw_cb(GUIWIN *win, uint16_t msg, GRECT *clip)
55{
56 struct gui_download_window *data;
57
58 if (msg != WM_REDRAW) {
59 data = gemtk_wm_get_user_data(win);
60
61 assert(data);
62
63 on_redraw(data, clip);
64 }
65}
66
67static short on_aes_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
68{
69 short retval = 0;
70 struct gui_download_window *data;
71
72 GRECT clip;
73
74 data = gemtk_wm_get_user_data(win);
75
76 if ((ev_out->emo_events & MU_MESAG) != 0) {
77 // handle message
78 //printf("download win msg: %d\n", msg[0]);
79 switch (msg[0]) {
80
81 case WM_REDRAW:
82 clip.g_x = msg[4];
83 clip.g_y = msg[5];
84 clip.g_w = msg[6];
85 clip.g_h = msg[7];
86 on_redraw(data, &clip);
87 break;
88
89 case WM_CLOSED:
90 // TODO: this needs to iterate through all gui windows and
91 // check if the rootwin is this window...
92 on_close(data);
93 break;
94
95 case WM_TOOLBAR:
96 switch(msg[4]){
97
98 case DOWNLOAD_BT_ABORT:
99 on_abort_click(data);
100 break;
101
102 case DOWNLOAD_CB_CLOSE_RDY:
103 on_cbrdy_click(data);
104 break;
105
106 default: break;
107 }
108 break;
109
110 default:
111 break;
112 }
113 }
114 if ((ev_out->emo_events & MU_KEYBD) != 0) {
115
116
117 }
118 if ((ev_out->emo_events & MU_BUTTON) != 0) {
119
120 }
121
122 return(retval);
123}
124
125static void on_redraw(struct gui_download_window *dw, GRECT *clip)
126{
127 OBJECT *tree = dw->tree;
128 GRECT work, visible;
129 uint32_t p = 0;
130
131 gemtk_wm_get_grect(dw->guiwin, GEMTK_WM_AREA_TOOLBAR, &work);
132 tree->ob_x = work.g_x;
133 tree->ob_y = work.g_y;
134
135 if(!rc_intersect(clip, &work)){
136 return;
137 }
138
139 /*
140 Update the AES Object to reflect current state of download:
141 */
142 ((TEDINFO *)get_obspec(tree, DOWNLOAD_FILENAME))->te_ptext = dw->lbl_file;
143 ((TEDINFO *)get_obspec(tree, DOWNLOAD_LBL_BYTES))->te_ptext = dw->lbl_done;
144 ((TEDINFO *)get_obspec(tree, DOWNLOAD_LBL_PERCENT))->te_ptext = dw->lbl_percent;
145 ((TEDINFO *)get_obspec(tree, DOWNLOAD_LBL_SPEED))->te_ptext = dw->lbl_speed;
146
147 if (dw->size_total > 0 ) {
148 p = ((double)dw->size_downloaded / (double)dw->size_total * 100);
149 }
150 tree[DOWNLOAD_PROGRESS_DONE].ob_width = MAX( MIN( p*(DOWNLOAD_BAR_MAX/100),
151 DOWNLOAD_BAR_MAX ), 1);
152 if (dw->close_on_finish) {
153 tree[DOWNLOAD_CB_CLOSE_RDY].ob_state |= (OS_SELECTED | OS_CROSSED);
154 } else {
155 tree[DOWNLOAD_CB_CLOSE_RDY].ob_state &= ~(OS_SELECTED | OS_CROSSED);
156 }
157 tree[DOWNLOAD_BT_ABORT].ob_state &= ~OS_SELECTED;
158
159 /*Walk the AES rectangle list and redraw the visible areas of the window: */
160 wind_get_grect(dw->aes_handle, WF_FIRSTXYWH, &visible);
161 while (visible.g_x && visible.g_y) {
162 if (rc_intersect(&work, &visible)) {
163 objc_draw_grect(tree, 0, 8, &visible);
164 }
165 wind_get_grect(dw->aes_handle, WF_NEXTXYWH, &visible);
166 }
167}
168
169static void on_abort_click(struct gui_download_window *dw)
170{
172 || dw->status == NSATARI_DOWNLOAD_ERROR ) {
173 gemtk_wm_send_msg(dw->guiwin, WM_CLOSED, 0,0,0,0);
174 }
175 else if( dw->status != NSATARI_DOWNLOAD_CANCELED ){
176 dw->abort = true;
177 }
178}
179
180static void on_cbrdy_click(struct gui_download_window *dw)
181{
184 gemtk_wm_send_msg(dw->guiwin, WM_CLOSED, 0,0,0,0);
185 }
186 gemtk_wm_exec_redraw(dw->guiwin, NULL);
187 evnt_timer(250);
188}
189
190static void on_close(struct gui_download_window * dw)
191{
193}
194
196{
197 NSLOG(netsurf, INFO, "gdw %p", gdw);
198
199 if (gdw->status == NSATARI_DOWNLOAD_WORKING) {
201 }
202
204
205 if (gdw->destination) {
206 free( gdw->destination );
207 }
208 if (gdw->fd != NULL) {
209 fclose(gdw->fd);
210 gdw->fd = NULL;
211 }
212 if (gdw->fbuf != NULL) {
213 free( gdw->fbuf );
214 }
215 gemtk_wm_remove(gdw->guiwin);
216 wind_close(gdw->aes_handle);
217 wind_delete(gdw->aes_handle);
218 free(gdw);
219}
220
221static char * select_filepath( const char * path, const char * filename )
222{
223 char tmp[PATH_MAX];
224 char res_path[PATH_MAX];
225 char res_file[PATH_MAX];
226 char * ret = NULL;
227
228 strncpy(res_path, path, PATH_MAX);
229 strncpy(res_file, filename, PATH_MAX);
230 res_file[PATH_MAX-1] = 0;
231 res_path[PATH_MAX-1] = 0;
232
233 if(select_file(res_path, res_file, (char*)"*",
234 (char*)messages_get("SaveAsNS"), NULL)) {
235 snprintf(tmp, PATH_MAX, "%s%s", res_path, res_file);
236 ret = malloc(strlen(tmp)+1);
237 strcpy(ret, tmp);
238 }
239
240 printf("download file: %s\n", ret);
241 return(ret);
242}
243
244static struct gui_download_window *
246{
247 const char *filename;
248 char *destination;
249 char gdos_path[PATH_MAX];
250 struct gui_download_window * gdw;
251 int dlgres = 0;
252 OBJECT * tree = gemtk_obj_get_tree(DOWNLOAD);
253 char alert[200];
254
255
256 NSLOG(netsurf, INFO, "Creating download window for gui window: %p",
257 parent);
258
259 /* TODO: Implement real form and use messages file strings! */
260
261 if (tree == NULL){
262 die("Couldn't find AES Object tree for download window!");
263 return(NULL);
264 }
265
267 snprintf(alert, 200, "[2][Accept download?|%.*s][Yes|Save as...|No]",
268 40,filename);
269 dlgres = form_alert(2, alert);
270 if( dlgres == 3){
271 return( NULL );
272 }
273 else if( dlgres == 2 ){
274 gemdos_realpath(nsoption_charp(downloads_path), gdos_path);
275 char * tmp = select_filepath( gdos_path, filename );
276 if( tmp == NULL )
277 return( NULL );
278 destination = tmp;
279 } else {
280 int dstsize=0;
281 gemdos_realpath(nsoption_charp(downloads_path), gdos_path);
282 dstsize = strlen(gdos_path) + strlen(filename) + 2;
283 destination = malloc( dstsize );
284 snprintf(destination, dstsize, "%s/%s", gdos_path, filename);
285 }
286
287 gdw = calloc(1, sizeof(struct gui_download_window));
288 if( gdw == NULL ){
289 atari_warn_user(NULL, "Out of memory!");
290 free( destination );
291 return( NULL );
292 }
293
294 gdw->ctx = ctx;
295 gdw->abort = false;
296 gdw->start = clock() / CLOCKS_PER_SEC;
297 gdw->lastrdw = 0;
299 gdw->parent = parent;
300 gdw->fbufsize = MAX(BUFSIZ, 48000);
301 gdw->size_downloaded = 0;
304 gdw->tree = tree;
305
306 gdw->fd = fopen(gdw->destination, "wb");
307 if( gdw->fd == NULL ){
308 char spare[200];
309 snprintf(spare, 200, "Couldn't open %s for writing!", gdw->destination);
310 gemtk_msg_box_show(GEMTK_MSG_BOX_ALERT, spare);
312 return( NULL );
313 }
314
315 gdw->fbuf = malloc( gdw->fbufsize+1 );
316 if( gdw->fbuf != NULL ){
317 setvbuf( gdw->fd, gdw->fbuf, _IOFBF, gdw->fbufsize );
318 }
319
320 gdw->aes_handle = wind_create_grect(CLOSER | NAME | MOVER, &desk_area);
321 wind_set_str(gdw->aes_handle, WF_NAME, "Download");
322 unsigned long gwflags = GEMTK_WM_FLAG_DEFAULTS;
323 gdw->guiwin = gemtk_wm_add(gdw->aes_handle, gwflags, on_aes_event);
324 if( gdw->guiwin == NULL || gdw->fd == NULL ){
325 die("could not create guiwin");
327 return( NULL );
328 }
329 gemtk_wm_set_user_data(gdw->guiwin, gdw);
330 gemtk_wm_set_toolbar(gdw->guiwin, tree, 0, 0);
331 gemtk_wm_set_toolbar_redraw_func(gdw->guiwin, toolbar_redraw_cb);
332
333 strncpy((char*)&gdw->lbl_file, filename, MAX_SLEN_LBL_FILE-1);
334 NSLOG(netsurf, INFO, "created download: %s (total size: %d)",
335 gdw->destination, gdw->size_total);
336
337 GRECT work, curr;
338 work.g_x = 0;
339 work.g_y = 0;
340 work.g_w = tree->ob_width;
341 work.g_h = tree->ob_height;
342
343 wind_calc_grect(WC_BORDER, CLOSER | MOVER | NAME, &work, &curr);
344
345 curr.g_x = (desk_area.g_w / 2) - (curr.g_w / 2);
346 curr.g_y = (desk_area.g_h / 2) - (curr.g_h / 2);
347
348 wind_open_grect(gdw->aes_handle, &curr);
349 gdw->lastrdw = clock() / (CLOCKS_PER_SEC >> 3);
350
351 return(gdw);
352}
353
354
356 const char *data, unsigned int size)
357{
358 uint32_t clck = clock();
359 uint32_t tnow = clck / (CLOCKS_PER_SEC>>3);
360 uint32_t sdiff = (clck / (CLOCKS_PER_SEC)) - dw->start;
361
362 NSLOG(netsurf, INFO, "dw %p", dw);
363
364 if (dw->abort == true){
366 dw->abort = false;
368 gemtk_wm_exec_redraw(dw->guiwin, NULL);
369 return(NSERROR_OK);
370 }
371
372 /* save data */
373 fwrite( data , size, sizeof(unsigned char),dw->fd );
374 dw->size_downloaded += size;
375
376 /* Update GUI */
377 if ((tnow - dw->lastrdw) > 1) {
378 float speed;
379
380 dw->lastrdw = tnow;
381 speed = dw->size_downloaded / sdiff;
382
383 if( dw->size_total > 0 ){
384 uint32_t p = 0;
385 p = ((double)dw->size_downloaded / (double)dw->size_total * 100);
386 snprintf( (char*)&dw->lbl_percent, MAX_SLEN_LBL_PERCENT,
387 "%"PRIu32"%s", p, "%"
388 );
389 } else {
390 snprintf( (char*)&dw->lbl_percent, MAX_SLEN_LBL_PERCENT,
391 "%s", "?%"
392 );
393 }
394 snprintf( (char*)&dw->lbl_speed, MAX_SLEN_LBL_SPEED, "%s/s",
396 );
397 snprintf( (char*)&dw->lbl_done, MAX_SLEN_LBL_DONE, "%s / %s",
400 );
401
402 gemtk_wm_exec_redraw(dw->guiwin, NULL);
403 }
404 return NSERROR_OK;
405}
406
408 const char *error_msg)
409{
410 NSLOG(netsurf, INFO, "%s", error_msg);
411
412 strncpy((char*)&dw->lbl_file, error_msg, MAX_SLEN_LBL_FILE-1);
414 gemtk_wm_exec_redraw(dw->guiwin, NULL);
416 // TODO: change abort to close
417}
418
420{
421 NSLOG(netsurf, INFO, "dw %p", dw);
422
423// TODO: change abort to close
425
426 if( dw->fd != NULL ) {
427 fclose( dw->fd );
428 dw->fd = NULL;
429 }
430
431 if (dw->close_on_finish) {
432 gemtk_wm_send_msg(dw->guiwin, WM_CLOSED, 0, 0, 0, 0);
433 } else {
434 snprintf( (char*)&dw->lbl_percent, MAX_SLEN_LBL_PERCENT,
435 "%u%s", 100, "%"
436 );
437 snprintf( (char*)&dw->lbl_done, MAX_SLEN_LBL_DONE, "%s / %s",
440 );
441 gemtk_wm_exec_redraw(dw->guiwin, NULL);
442 }
444}
445
451};
452
void atari_window_set_status(struct gui_window *w, const char *text)
Set the status bar of a browser window.
Definition: gui.c:356
#define PATH_MAX
Definition: gui.h:31
void die(const char *error)
Cause an abnormal program termination.
Definition: misc.c:69
nserror atari_warn_user(const char *warning, const char *detail)
Warn the user of an event.
Definition: misc.c:56
Browser window creation and manipulation interface.
void download_context_destroy(download_context *ctx)
Destroy a download context.
Definition: download.c:270
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)
wimp_w parent
Definition: dialog.c:88
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_OK
No error.
Definition: errors.h:30
static char * select_filepath(const char *path, const char *filename)
Definition: download.c:221
static void gui_download_window_destroy(struct gui_download_window *gdw)
Definition: download.c:195
static struct gui_download_table download_table
Definition: download.c:446
GRECT desk_area
Definition: gui.c:79
static short on_aes_event(GUIWIN *win, EVMULT_OUT *ev_out, short msg[8])
Definition: download.c:67
struct gui_window * input_window
Definition: gui.c:74
static nserror gui_download_window_data(struct gui_download_window *dw, const char *data, unsigned int size)
Definition: download.c:355
static void on_cbrdy_click(struct gui_download_window *dw)
Definition: download.c:180
static void on_close(struct gui_download_window *dw)
Definition: download.c:190
static void gui_download_window_error(struct gui_download_window *dw, const char *error_msg)
Definition: download.c:407
static void toolbar_redraw_cb(GUIWIN *win, uint16_t msg, GRECT *clip)
Definition: download.c:54
static void on_abort_click(struct gui_download_window *dw)
Definition: download.c:169
static void gui_download_window_done(struct gui_download_window *dw)
Definition: download.c:419
struct gui_download_table * atari_download_table
Definition: download.c:453
static void on_redraw(struct gui_download_window *dw, GRECT *clip)
Definition: download.c:125
static struct gui_download_window * gui_download_window_create(download_context *ctx, struct gui_window *parent)
Definition: download.c:245
#define DOWNLOAD_BAR_MAX
Definition: download.h:30
@ NSATARI_DOWNLOAD_CANCELED
Definition: download.h:37
@ NSATARI_DOWNLOAD_COMPLETE
Definition: download.h:36
@ NSATARI_DOWNLOAD_ERROR
Definition: download.h:35
@ NSATARI_DOWNLOAD_WORKING
Definition: download.h:34
#define MAX_SLEN_LBL_PERCENT
Definition: download.h:25
#define MAX_SLEN_LBL_FILE
Definition: download.h:27
#define MAX_SLEN_LBL_DONE
Definition: download.h:24
#define MAX_SLEN_LBL_SPEED
Definition: download.h:26
Interface to platform-specific download operations.
Netsurf additional integer type formatting macros.
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
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).
#define MIN(a, b)
Definition: os3support.h:51
char * gemdos_realpath(const char *path, char *rpath)
Definition: osspec.c:107
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
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
char lbl_speed[MAX_SLEN_LBL_SPEED]
Definition: download.h:51
struct gui_window * parent
Definition: download.h:42
uint32_t size_total
Definition: download.h:55
uint32_t size_downloaded
Definition: download.h:56
uint32_t lastrdw
Definition: download.h:54
nsatari_download_status status
Definition: download.h:46
char * destination
Definition: download.h:47
char lbl_done[MAX_SLEN_LBL_DONE]
Definition: download.h:49
GUIWIN * guiwin
Definition: download.h:43
struct download_context * ctx
Associated context, or 0 if the fetch has completed or aborted.
Definition: download.c:101
char lbl_file[MAX_SLEN_LBL_FILE]
Definition: download.h:52
char lbl_percent[MAX_SLEN_LBL_PERCENT]
Definition: download.h:50
struct Window * win
Definition: download.c:93
uint32_t start
Definition: download.h:53
first entry in window list
Definition: gui.c:298
Interface to time operations.
Option reading and saving interface.
#define nsoption_charp(OPTION)
Get the value of a string option.
Definition: nsoption.h:331
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821
static nserror clip(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plot.c:357