[links-list] Re: Graphical Links with extra features

William Yodlowsky wyodlows at andromeda.rutgers.edu
Sat Nov 30 17:39:15 PST 2002


<smack>

Of course, I forgot the patch and file  :-(

Sorry about that.  Attached, this time...

-------------- next part --------------
*** Makefile.in.orig	Sat Nov 30 19:09:42 2002
--- Makefile.in	Sat Nov 30 19:10:09 2002
***************
*** 98,104 ****
  language.o links_icon.o listedit.o lru.o mailto.o main.o menu.o \
  memory.o md5.o md5hl.o ns.o objreq.o os_dep.o pmshell.o png.o pomocny.o \
  sched.o select.o session.o svgalib.o terminal.o tiff.o types.o url.o \
! view.o view_gr.o win32.o x.o xbm.o
  @ATHEOS_GR_TRUE at links_DEPENDENCIES =  atheos.o
  links_LDFLAGS = 
  CFLAGS = @CFLAGS@
--- 98,104 ----
  language.o links_icon.o listedit.o lru.o mailto.o main.o menu.o \
  memory.o md5.o md5hl.o ns.o objreq.o os_dep.o pmshell.o png.o pomocny.o \
  sched.o select.o session.o svgalib.o terminal.o tiff.o types.o url.o \
! view.o view_gr.o win32.o x.o xbm.o auth.o
  @ATHEOS_GR_TRUE at links_DEPENDENCIES =  atheos.o
  links_LDFLAGS = 
  CFLAGS = @CFLAGS@
*** bfu.c.orig	Sat Nov 30 19:44:27 2002
--- bfu.c	Sat Nov 30 19:53:19 2002
***************
*** 786,796 ****
  			}
  			break;
  		case D_FIELD:
  			if (di->vpos + di->l <= di->cpos) di->vpos = di->cpos - di->l + 1;
  			if (di->vpos > di->cpos) di->vpos = di->cpos;
  			if (di->vpos < 0) di->vpos = 0;
  			fill_area(term, di->x, di->y, di->l, 1, COLOR_DIALOG_FIELD);
! 			print_text(term, di->x, di->y, strlen(di->cdata + di->vpos) <= di->l ? strlen(di->cdata + di->vpos) : di->l, di->cdata + di->vpos, COLOR_DIALOG_FIELD_TEXT);
  			if (sel) {
  				set_cursor(term, di->x + di->cpos - di->vpos, di->y, di->x + di->cpos - di->vpos, di->y);
  				set_window_ptr(dlg->win, di->x, di->y);
--- 786,803 ----
  			}
  			break;
  		case D_FIELD:
+ 		case D_FIELD_PASS:
  			if (di->vpos + di->l <= di->cpos) di->vpos = di->cpos - di->l + 1;
  			if (di->vpos > di->cpos) di->vpos = di->cpos;
  			if (di->vpos < 0) di->vpos = 0;
  			fill_area(term, di->x, di->y, di->l, 1, COLOR_DIALOG_FIELD);
!                         if (di->item->type == D_FIELD) {
!                             print_text(term, di->x, di->y, strlen(di->cdata + di->vpos) <= di->l ? strlen(di->cdata + di->vpos) : di->l, di->cdata + di->vpos, COLOR_DIALOG_FIELD_TEXT);
!                         } else {
!                             fill_area(term, di->x, di->y,
!                                       strlen(di->cdata + di->vpos) <= di->l ? strlen(di->cdata + di->vpos) : di->l, 1,
!                                       COLOR_DIALOG_FIELD_TEXT | '*');
!                         }
  			if (sel) {
  				set_cursor(term, di->x + di->cpos - di->vpos, di->y, di->x + di->cpos - di->vpos, di->y);
  				set_window_ptr(dlg->win, di->x, di->y);
***************
*** 817,823 ****
  		switch (di->item->type) {
  			int p, pp;
  			struct style *st;
! 			unsigned char *text, *text2, *text3;
  			struct rect r;
  			case D_CHECKBOX:
  				p = di->x;
--- 824,830 ----
  		switch (di->item->type) {
  			int p, pp;
  			struct style *st;
! 			unsigned char *text, *text2, *text3, *text_pass;
  			struct rect r;
  			case D_CHECKBOX:
  				p = di->x;
***************
*** 845,852 ****
  				if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, p, di->y + G_BFU_FONT_SIZE);
  				break;
  			case D_FIELD:
  				if (!(text = memacpy(di->cdata, di->cpos))) break;
! 				if (*(text2 = text3 = di->cdata + di->cpos)) {
  					GET_UTF_8(text3, p);
  					text2 = memacpy(text2, text3 - text2);
  				} else {
--- 852,862 ----
  				if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, p, di->y + G_BFU_FONT_SIZE);
  				break;
  			case D_FIELD:
+ 			case D_FIELD_PASS:
  				if (!(text = memacpy(di->cdata, di->cpos))) break;
!                                 text_pass=mem_alloc(di->cpos+1);
!                                 for(pp=0;pp<di->cpos;pp++) text_pass[pp]='*';text_pass[pp]='\0';
!                                 if (*(text2 = text3 = di->cdata + di->cpos)) {
  					GET_UTF_8(text3, p);
  					text2 = memacpy(text2, text3 - text2);
  				} else {
***************
*** 866,874 ****
  				if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
  				restrict_clip_area(dev, &r, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
  				p = di->x - di->vpos;
! 				g_print_text(drv, dev, p, di->y, bfu_style_wb_mono, text, &p);
! 				g_print_text(drv, dev, p, di->y, sel ? bfu_style_wb_mono_u : bfu_style_wb_mono, text2, &p);
  				g_print_text(drv, dev, p, di->y, bfu_style_wb_mono, text3, &p);
  				drv->fill_area(dev, p, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE, bfu_fg_color);
  				drv->set_clip_area(dev, &r);
  				mem_free(text);
--- 876,891 ----
  				if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
  				restrict_clip_area(dev, &r, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
  				p = di->x - di->vpos;
!                                 if (di->item->type == D_FIELD) {
!                                     g_print_text(drv, dev, p, di->y, bfu_style_wb_mono, text, &p);
!                                 } else {
!                                     g_print_text(drv, dev, p, di->y, bfu_style_wb_mono, text_pass, &p);
!                                 }
!                                 mem_free(text_pass);
!                                 g_print_text(drv, dev, p, di->y, sel ? bfu_style_wb_mono_u : bfu_style_wb_mono, text2, &p);
  				g_print_text(drv, dev, p, di->y, bfu_style_wb_mono, text3, &p);
+ 
+ 
  				drv->fill_area(dev, p, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE, bfu_fg_color);
  				drv->set_clip_area(dev, &r);
  				mem_free(text);
***************
*** 963,968 ****
--- 980,986 ----
  			if ((ev->b & BM_ACT) == B_UP) dlg_select_item(dlg, di);
  			return 1;
  		case D_FIELD:
+ 		case D_FIELD_PASS:
  			if (gf_val(ev->y != di->y, ev->y < di->y || ev->y >= di->y + G_BFU_FONT_SIZE) || ev->x < di->x || ev->x >= di->x + di->l) return 0;
  			if (!F) {
  				if ((di->cpos = di->vpos + ev->x - di->x) > strlen(di->cdata)) di->cpos = strlen(di->cdata);
***************
*** 1103,1109 ****
  				} 
  				init_list(di->history);
  				di->cur_hist = (struct history_item *)&di->history;
! 				if (di->item->type == D_FIELD) {
  					if (di->item->history) {
  						struct history_item *j;
  						/*int l = di->item->dlen;*/
--- 1121,1127 ----
  				} 
  				init_list(di->history);
  				di->cur_hist = (struct history_item *)&di->history;
!                                if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) {
  					if (di->item->history) {
  						struct history_item *j;
  						/*int l = di->item->dlen;*/
***************
*** 1130,1136 ****
  			break;
  		case EV_KBD:
  			di = &dlg->items[dlg->selected];
! 			if (di->item->type == D_FIELD) {
  				if (ev->x == KBD_UP && (void *)di->cur_hist->prev != &di->history) {
  					di->cur_hist = di->cur_hist->prev;
  					dlg_set_history(di);
--- 1148,1154 ----
  			break;
  		case EV_KBD:
  			di = &dlg->items[dlg->selected];
!                         if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) {
  				if (ev->x == KBD_UP && (void *)di->cur_hist->prev != &di->history) {
  					di->cur_hist = di->cur_hist->prev;
  					dlg_set_history(di);
***************
*** 1353,1359 ****
  {
  	int i;
  	for (i = 0; i < dlg->n; i++)
! 		if (dlg->dlg->items[i].type == D_CHECKBOX || dlg->dlg->items[i].type == D_FIELD)
  			if (dlg->dlg->items[i].fn && dlg->dlg->items[i].fn(dlg, &dlg->items[i])) {
  				dlg->selected = i;
  				draw_to_window(dlg->win, (void (*)(struct terminal *, void *))redraw_dialog_items, dlg);
--- 1371,1377 ----
  {
  	int i;
  	for (i = 0; i < dlg->n; i++)
!                 if (dlg->dlg->items[i].type == D_CHECKBOX || dlg->dlg->items[i].type == D_FIELD || dlg->dlg->items[i].type == D_FIELD_PASS) 
  			if (dlg->dlg->items[i].fn && dlg->dlg->items[i].fn(dlg, &dlg->items[i])) {
  				dlg->selected = i;
  				draw_to_window(dlg->win, (void (*)(struct terminal *, void *))redraw_dialog_items, dlg);
***************
*** 1738,1744 ****
  #endif
  			item->x = x + nx + sl * (item->item->type != D_CHECKBOX);
  			item->y = *y;
! 			if (item->item->type == D_FIELD) item->l = gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
  		}
  		if (rw && nx + wx > *rw) if ((*rw = nx + wx) > w) *rw = w;
  		nx += wx + gf_val(1, G_DIALOG_GROUP_SPACE);
--- 1756,1762 ----
  #endif
  			item->x = x + nx + sl * (item->item->type != D_CHECKBOX);
  			item->y = *y;
!                         if (item->item->type == D_FIELD || item->item->type == D_FIELD_PASS) item->l = gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
  		}
  		if (rw && nx + wx > *rw) if ((*rw = nx + wx) > w) *rw = w;
  		nx += wx + gf_val(1, G_DIALOG_GROUP_SPACE);
*** http.c.orig	Sat Nov 30 18:50:39 2002
--- http.c	Sat Nov 30 18:48:28 2002
***************
*** 157,162 ****
--- 157,163 ----
  	int l = 0;
  	unsigned char *post;
  	unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url);
+ 	unsigned char *host_data;
  	set_timeout(c);
  	if (!(info = mem_alloc(sizeof(struct http_connection_info)))) {
  		setcstate(c, S_OUT_OF_MEM);
***************
*** 306,311 ****
--- 307,320 ----
  		add_num_to_str(&hdr, &l, c->from);
  		add_to_str(&hdr, &l, "-\r\n");
  	}
+ 	host_data = find_auth(host);
+ 	if (host_data) {
+ 		add_to_str(&hdr, &l, "Authorization: Basic ");
+ 		add_to_str(&hdr, &l, host_data);
+ 		add_to_str(&hdr, &l, "\r\n");
+ 		mem_free(host_data);
+ 	}
+ 
  	if (post) {
  		unsigned char *pd = strchr(post, '\n');
  		if (pd) {
***************
*** 564,569 ****
--- 573,595 ----
  			e->redirect_get = h == 303;
  		}
  	}
+  	if (h == 401) {
+ 		d = parse_http_header(e->head, "WWW-Authenticate", NULL);
+ 		if (d) {
+ 			if (!strncasecmp(d, "Basic", 5)) {
+ 				unsigned char *realm = get_http_header_param(d, "realm");
+ 
+ 				if (realm) {
+ 					if (add_auth_entry(host, realm) > 0) {
+                                             need_auth=1;
+                                         }
+ 					mem_free(realm);
+ 				}
+ 			}
+ 			mem_free(d);
+ 		}
+   	}
+ 
  	kill_buffer_data(rb, a);
  	c->cache = e;
  	info->close = 0;
*** links.h.orig	Sat Nov 30 19:27:22 2002
--- links.h	Sat Nov 30 19:27:52 2002
***************
*** 2961,2967 ****
  #define D_END		0
  #define D_CHECKBOX	1
  #define D_FIELD		2
! #define D_BUTTON	3
  
  #define B_ENTER		1
  #define B_ESC		2
--- 2961,2968 ----
  #define D_END		0
  #define D_CHECKBOX	1
  #define D_FIELD		2
! #define D_FIELD_PASS	3
! #define D_BUTTON	4
  
  #define B_ENTER		1
  #define B_ESC		2
***************
*** 3876,3880 ****
--- 3877,3906 ----
  
  /* Launches bookmark manager */
  void menu_bookmark_manager(struct terminal *, void *, struct session *);
+ 
+ /* auth.h */
+ 
+ struct http_auth_basic {
+         struct http_auth_basic *next;
+         struct http_auth_basic *prev;
+         int blocked;
+         int valid;
+         unsigned char *url;
+         int url_len;
+         unsigned char *realm;
+         unsigned char *uid;
+         unsigned char *passwd;
+ };
+ 
+ void init_auth();
+ unsigned char *find_auth(unsigned char *);
+ int add_auth_entry(unsigned char *, unsigned char *);
+ void del_auth_entry(struct http_auth_basic *);
+ void free_auth();
+ unsigned char *base64_encode(unsigned char *);
+ unsigned char *get_http_header_param(unsigned char *e, unsigned char * name);
+ void do_auth_dialog(struct session *ses);
+ 
+ int need_auth;
  
  #endif /* #ifndef _LINKS_H */
*** main.c.orig	Sat Nov 30 18:51:54 2002
--- main.c	Sat Nov 30 18:53:07 2002
***************
*** 351,356 ****
--- 351,357 ----
  	init_dns();
  	init_cache();
  	iinit_bfu();
+ 	init_auth();
  }
  
  /* Is called sometimes after and sometimes before graphics driver init */
***************
*** 385,390 ****
--- 386,392 ----
  	free_history_lists();
  	free_term_specs();
  	free_types();
+ 	free_auth();
  	if (init_b) finalize_bookmarks();
  	free_conv_table();
  	free_blacklist();
*** session.c.orig	Sat Nov 30 18:53:37 2002
--- session.c	Sat Nov 30 18:54:30 2002
***************
*** 156,161 ****
--- 156,165 ----
  		set_terminal_title(ses->term, m);
  		/*mem_free(m); -- set_terminal_title frees it */
  	}
+ 	if (need_auth==1) {
+ 	    need_auth=0;
+ 	    do_auth_dialog(ses);
+ 	}
  }
  
  void print_error_dialog(struct session *ses, struct status *stat, unsigned char *title)
*** setup.h.orig	Sat Nov 30 18:55:10 2002
--- setup.h	Sat Nov 30 18:55:43 2002
***************
*** 187,189 ****
--- 187,191 ----
  #define MOUSE_SCROLL_DIVIDER          1
  
  #define MAGICKA_KONSTANTA_NA_MAXIMALNI_DYLKU_JS_KODU_PRI_ERRORU	256
+ #define MAX_UID_LEN                    20
+ #define MAX_PASSWD_LEN                 20
-------------- next part --------------
/* HTTP Authentication support */ 
#include "links.h"

#define WHITECHAR(x) ((x) == ' ' || ((x) >= 9 && (x) <= 13))
#define IS_QUOTE(x) ((x) == '"' || (x) == '\'')


struct list_head http_auth_basic_list = { &http_auth_basic_list, &http_auth_basic_list };


void init_auth()
{
    need_auth=0;
}

/* Returns a valid host url for http authentification or NULL. */
/* FIXME: This really belongs to url.c, but it would look alien there. */
static unsigned char *
get_auth_url(unsigned char *url)
{
        unsigned char *protocol = get_protocol_name(url);
        unsigned char *host = get_host_name(url);
        unsigned char *port = get_port_str(url);
        unsigned char *newurl = NULL;

        /* protocol == NULL is tested in straconcat() */;
        newurl = straconcat(protocol, "://", host, NULL);
        if (!newurl) goto end;

        if (port && *port) {
                add_to_strn(&newurl, ":");
                add_to_strn(&newurl, port);
        } else {
                if (!strcasecmp(protocol, "http")) {
                        /* RFC2616 section 3.2.2
                         * If the port is empty or not given, port 80 is
                         * assumed. */
                        add_to_strn(&newurl, ":");
                        add_to_strn(&newurl, "80");
                } else if (!strcasecmp(protocol, "https")) {
                        add_to_strn(&newurl, ":");
                        add_to_strn(&newurl, "443");
                }
        }

end:
        if (protocol) mem_free(protocol);
        if (host) mem_free(host);
        if (port) mem_free(port);

        return newurl;
}


/* Find if url/realm is in auth list. If a matching url is found, but realm is
 * NULL, it returns the first record found. If realm isn't NULL, it returns
 * the first record that matches exactly (url and realm) if any. */
struct http_auth_basic *
find_auth_entry(unsigned char *url, unsigned char *realm)
{
        struct http_auth_basic *entry = NULL, *tmp_entry;

        if (!url || !*url) return NULL;

        foreach(tmp_entry, http_auth_basic_list) {
                if (!strcasecmp(tmp_entry->url, url)) {
                        /* Found a matching url. */
                        entry = tmp_entry;
                        if (realm) {
                                /* From RFC 2617 section 1.2:
                                 * The realm value (case-sensitive), in
                                 * combination with the canonical root
                                 * URL (the absolute URI for the server
                                 * whose abs_path is empty; see section
                                 * 5.1.2 of [2]) of the server being accessed,
                                 * defines the protection space. */
                                if (tmp_entry->realm
                                    && !strcmp(tmp_entry->realm, realm)) {
                                        /* Exact match. */
                                        break; /* Stop here. */
                                }
                        } else {
                                /* Since realm is NULL, stops immediatly. */
                                break;
                        }
                }
        }

        return entry;
}

/* Add a Basic Auth entry if needed. Returns -1 on error, 0 if entry do not
 * exists and user/pass are in url, 1 if exact entry already exists or is
 * in blocked state, 2 if entry was added. */
/* FIXME: use an enum for return codes. */
int
add_auth_entry(unsigned char *url, unsigned char *realm)
{
        struct http_auth_basic *entry;
        unsigned char *user = get_user_name(url);
        unsigned char *pass = get_pass(url);
        unsigned char *newurl = get_auth_url(url);
        int ret = -1;

        if (!newurl || !user || !pass) goto end;

        /* Is host/realm already known ? */
        entry = find_auth_entry(newurl, realm);
        if (entry) {
                /* Found an entry. */
                if (entry->blocked == 1) {
                        /* Waiting for user/pass in dialog. */
                        ret = 1;
                        goto end;
                }

                /* If we have user/pass info then check if identical to
                 * those in entry. */
                if ((*user || *pass) && entry->uid && entry->passwd) {
                        if (((!realm && !entry->realm)
                             || (realm && entry->realm
                                 && !strcmp(realm, entry->realm)))
                            && !strcmp(user, entry->uid)
                            && !strcmp(pass, entry->passwd)) {
                                /* Same host/realm/pass/user. */
                                ret = 1;
                                goto end;
                        }
                }

                /* Delete entry and re-create it... */
                /* FIXME: Could be better... */
                del_auth_entry(entry);
        }

        /* Create a new entry. */
        entry = mem_alloc(sizeof(struct http_auth_basic));
        if (!entry) goto end;
        memset(entry, 0, sizeof(struct http_auth_basic));

        entry->url = newurl;
        entry->url_len = strlen(entry->url); /* FIXME: Not really needed. */

        if (realm) {
                /* Copy realm value. */
                entry->realm = stracpy(realm);
                if (!entry->realm) {
                        mem_free(entry);
                        goto end;
                }
        }

        if (*user || *pass) {
                /* Copy user and pass info if any in passed url. */
                entry->uid = mem_alloc(MAX_UID_LEN);
                if (!entry->uid) {
                        mem_free(entry);
                        goto end;
                }
                safe_strncpy(entry->uid, user, MAX_UID_LEN);

                entry->passwd = mem_alloc(MAX_PASSWD_LEN);
                if (!entry->passwd) {
                        mem_free(entry);
                        goto end;
                }
                safe_strncpy(entry->passwd, pass, MAX_PASSWD_LEN);

                ret = 0; /* Entry added with user/pass from url. */
        }

        add_to_list(http_auth_basic_list, entry);

        if (ret) ret = 2; /* Entry added. */

end:
        if (ret == -1 || ret == 1) {
               if (newurl) mem_free(newurl);
        }

        if (user) mem_free(user);
        if (pass) mem_free(pass);

        return ret;
}

/* Find an entry in auth list by url. If url contains user/pass information
 * and entry does not exist then entry is created.
 * If entry exists but user/pass passed in url is different, then entry is
 * updated (but not if user/pass is set in dialog).
 * It returns NULL on failure, or a base 64 encoded user + pass suitable to
 * use in Authorization header. */
unsigned char *
find_auth(unsigned char *url)
{
        struct http_auth_basic *entry = NULL;
        unsigned char *uid, *ret = NULL;
        unsigned char *newurl = get_auth_url(url);
        unsigned char *user = get_user_name(url);
        unsigned char *pass = get_pass(url);

        if (!newurl) goto end;

again:
        entry = find_auth_entry(newurl, NULL);

        /* Check is user/pass info is in url. */
        if ((user && *user) || (pass && *pass)) {
                /* If we've got an entry, but with different user/pass or no
                 * entry, then we try to create or modify it and retry. */
                if ((entry && !entry->valid && entry->uid && entry->passwd
                     && (strcmp(user, entry->uid) || strcmp(pass, entry->passwd)))
                    || !entry) {
                        if (add_auth_entry(url, NULL) == 0) {
                                /* An entry was re-created, we free user/pass
                                 * before retry to prevent infinite loop. */
                                if (user) {
                                        mem_free(user);
                                        user = NULL;
                                }
                                if (pass) {
                                        mem_free(pass);
                                        pass = NULL;
                                }
                                goto again;
                        }
                }
        }

        /* No entry found. */
        if (!entry) goto end;

        /* Sanity check. */
        if (!entry->passwd || !entry->uid) {
                del_auth_entry(entry);
                goto end;
        }

        /* RFC2617 section 2 [Basic Authentication Scheme]
         * To receive authorization, the client sends the userid and password,
         * separated by a single colon (":") character, within a base64 [7]
         * encoded string in the credentials. */

        /* Create base64 encoded string. */
        uid = straconcat(entry->uid, ":", entry->passwd, NULL);
        if (!uid) goto end;

        ret = base64_encode(uid);
        mem_free(uid);

end:
        if (newurl) mem_free(newurl);
        if (user) mem_free(user);
        if (pass) mem_free(pass);

        return ret;
}

/* Delete an entry from auth list. */
void
del_auth_entry(struct http_auth_basic *entry)
{
        if (entry->url) mem_free(entry->url);
        if (entry->realm) mem_free(entry->realm);
        if (entry->uid) mem_free(entry->uid);
        if (entry->passwd) mem_free(entry->passwd);
        del_from_list(entry);
        mem_free(entry);
}

/* Free all entries in auth list and questions in queue. */
void
free_auth()
{
        while (!list_empty(http_auth_basic_list))
                del_auth_entry(http_auth_basic_list.next);
}

unsigned char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

unsigned char *base64_encode(unsigned char *in)
{
	unsigned char *out, *outstr;
	int inlen = strlen(in);
	
	outstr = out = mem_alloc(((inlen / 3) + 1) * 4 + 1 );
	if (!outstr) return NULL;

	while (inlen >= 3) {
		*out++ = base64_chars[(int) (*in >> 2) ];
		*out++ = base64_chars[(int) ((*in << 4 | *(in + 1) >> 4) & 63) ];
		*out++ = base64_chars[(int) ((*(in + 1) << 2 | *(in + 2) >> 6) & 63) ];
		*out++ = base64_chars[(int) (*(in + 2) & 63) ];
		inlen -= 3; in += 3;
	}
	if (inlen == 1) {
		*out++ = base64_chars[(int) (*in >> 2) ];
		*out++ = base64_chars[(int) (*in << 4 & 63) ];
		*out++ = '=';
		*out++ = '=';
	}
	if (inlen == 2) {
		*out++ = base64_chars[(int) (*in >> 2) ];
		*out++ = base64_chars[(int) ((*in << 4 | *(in + 1) >> 4) & 63) ];
		*out++ = base64_chars[(int) ((*(in + 1) << 2) & 63) ];
		*out++ = '=';
	}
	*out = 0;
	
	return outstr;
}

/* Parse string param="value", return value as new string or NULL if any
 * error. */
unsigned char *get_http_header_param(unsigned char *e, unsigned char *name)
{
	unsigned char *n, *start;
	int i = 0;

again:
	while (*e && upcase(*e++) != upcase(*name));
	if (!*e) return NULL;
	n = name + 1;
	while (*n && upcase(*e) == upcase(*n)) e++, n++;
	if (*n) goto again;
	while (WHITECHAR(*e)) e++;
	if (*e++ != '=') return NULL;
	while (WHITECHAR(*e)) e++;

	start = e;
	if (!IS_QUOTE(*e)) while (*e && !WHITECHAR(*e)) e++;
	else {
		char uu = *e++;

		start++;
		while (*e != uu) {
			if (!*e) return NULL;
			e++;
		}
	}

	while (start < e && *start == ' ') start++;
	while (start < e && *(e - 1) == ' ') e--;
	if (start == e) return NULL;

	n = mem_alloc(e - start + 1);
	if (!n) return NULL;
	while (start < e) {
		if (*start < ' ') n[i] = '.';
		else n[i] = *start;
		i++; start++;
	}
	n[i] = 0;

	return n;
}

/* Auth dialog */

void
auth_layout(struct dialog_data *dlg)
{
        struct terminal *term = dlg->win->term;
        int max = 0, min = 0;
        int w, rw;
        int y = -1;

	max_text_width(term, TEXT(T_USERID), &max, AL_LEFT);
        min_text_width(term, TEXT(T_USERID), &min, AL_LEFT);
        max_text_width(term, TEXT(T_PASSWORD), &max, AL_LEFT);
        min_text_width(term, TEXT(T_PASSWORD), &min, AL_LEFT);
        max_buttons_width(term, dlg->items + 2, 2,  &max);
        min_buttons_width(term, dlg->items + 2, 2,  &min);

        w = dlg->win->term->x * 9 / 10 - 2 * DIALOG_LB;
        if (w < min) w = min;
        if (w > dlg->win->term->x - 2 * DIALOG_LB) w = dlg->win->term->x - 2 * DIALOG_LB;
        if (w < 1) w = 1;
        rw = 0;
        if (dlg->dlg->udata) {
                dlg_format_text(dlg, NULL, dlg->dlg->udata, 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
                y += gf_val(1, G_BFU_FONT_SIZE);
        }

        dlg_format_text(dlg, NULL, TEXT(T_USERID), 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
	y += gf_val(2, G_BFU_FONT_SIZE*2);
        dlg_format_text(dlg, NULL, TEXT(T_PASSWORD), 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
	y += gf_val(2, G_BFU_FONT_SIZE*2);
        dlg_format_buttons(dlg, NULL, dlg->items + 2, 2, 0, &y, w, &rw, AL_CENTER);
        w = rw;
        dlg->xw = w + 2 * DIALOG_LB;
        dlg->yw = y + 2 * DIALOG_TB;
        center_dlg(dlg);
        draw_dlg(dlg);
        y = dlg->y + DIALOG_TB;
        if (dlg->dlg->udata) {
                dlg_format_text(dlg, term, dlg->dlg->udata, dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
                y += gf_val(1, G_BFU_FONT_SIZE);
        }
        dlg_format_text(dlg, term, TEXT(T_USERID), dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
        dlg_format_field(dlg, term, &dlg->items[0], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
	y += gf_val(1, G_BFU_FONT_SIZE);
        dlg_format_text(dlg, term, TEXT(T_PASSWORD), dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
        dlg_format_field(dlg, term, &dlg->items[1], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
	y += gf_val(1, G_BFU_FONT_SIZE);
        dlg_format_buttons(dlg, term, &dlg->items[2], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
}

int
auth_ok(struct dialog_data *dlg, struct dialog_item_data *di)
{
        ((struct http_auth_basic *)dlg->dlg->udata2)->blocked = 0;
        reload(dlg->dlg->refresh_data, -1);
        return ok_dialog(dlg, di);
}

int
auth_cancel(struct dialog_data *dlg, struct dialog_item_data *di)
{
        ((struct http_auth_basic *)dlg->dlg->udata2)->blocked = 0;
        del_auth_entry(dlg->dlg->udata2);
        return cancel_dialog(dlg, di);
}

/* FIXME: This should be exported properly. --pasky */
extern struct list_head http_auth_basic_list;

void
do_auth_dialog(struct session *ses)
{
        /* TODO: complete rewrite */
        struct dialog *d;
        struct terminal *term = ses->term;
        struct http_auth_basic *a = NULL;

        if (!list_empty(http_auth_basic_list)
            && !((struct http_auth_basic *) http_auth_basic_list.next)->valid)
                a = (struct http_auth_basic *) http_auth_basic_list.next;
        if (!a || a->blocked) return;
        a->valid = 1;
        a->blocked = 1;
        if (!a->uid) {
                if (!(a->uid = mem_alloc(MAX_UID_LEN))) {
                        del_auth_entry(a);
                        return;
                }
                *a->uid = 0;
        }
        if (!a->passwd) {
                if (!(a->passwd = mem_alloc(MAX_PASSWD_LEN))) {
                        del_auth_entry(a);
                        return;
                }
                *a->passwd = 0;
        }
        d = mem_alloc(sizeof(struct dialog) + 5 * sizeof(struct dialog_item)
                      + strlen(_(TEXT(T_ENTER_USERNAME), term))
                      + (a->realm ? strlen(a->realm) : 0)
                      + strlen(_(TEXT(T_AT), term)) + strlen(a->url) + 1);
        if (!d) return;
        memset(d, 0, sizeof(struct dialog) + 5 * sizeof(struct dialog_item));
        d->title = TEXT(T_USERID);
        d->fn = auth_layout;

        d->udata = (char *)d + sizeof(struct dialog) + 5 * sizeof(struct dialog_item);
        strcpy(d->udata, _(TEXT(T_ENTER_USERNAME), term));
        if (a->realm) strcat(d->udata, a->realm);
        strcat(d->udata, _(TEXT(T_AT), term));
        strcat(d->udata, a->url);

        d->udata2 = a;
        d->refresh_data = ses;

        d->items[0].type = D_FIELD;
        d->items[0].dlen = MAX_UID_LEN;
        d->items[0].data = a->uid;

        d->items[1].type = D_FIELD_PASS;
        d->items[1].dlen = MAX_PASSWD_LEN;
        d->items[1].data = a->passwd;

        d->items[2].type = D_BUTTON;
        d->items[2].gid = B_ENTER;
        d->items[2].fn = auth_ok;
        d->items[2].text = TEXT(T_OK);

        d->items[3].type = D_BUTTON;
        d->items[3].gid = B_ESC;
        d->items[3].fn = auth_cancel;
        d->items[3].text = TEXT(T_CANCEL);

        d->items[4].type = D_END;
        do_dialog(term, d, getml(d, NULL));
        a->blocked = 0;

}

/* Concatenate all strings parameters. Parameters list must _always_ be
 * terminated by a NULL pointer.  If first parameter is NULL or allocation
 * failure, return NULL.  On success, returns a pointer to a dynamically
 * allocated string.
 *
 * Example:
 * ...
 * unsigned char *s = straconcat("A", "B", "C", NULL);
 * if (!s) return;
 * printf("%s", s); -> print "ABC"
 * mem_free(s); -> free memory used by s
 */
unsigned char *
straconcat(unsigned char *str, ...)
{
	va_list ap;
	unsigned char *a;
	unsigned char *s;
	unsigned int len;

	if (!str) return NULL;

	s = stracpy(str);
	if (!s) return NULL;

	len = strlen(s) + 1;

	va_start(ap, str);
	while ((a = va_arg(ap, unsigned char *))) {
		unsigned char *p;

		len += strlen(a);
		p = mem_realloc(s, len);
		if (!p) {
			mem_free(s);
			va_end(ap);
			return NULL;
		}
		s = p;
		strcat(s, a);
	}

	va_end(ap);

	return s;
}


More information about the links-list mailing list