void dispatch_special(unsigned char *text) { switch (text[0]) { case TERM_FN_TITLE: if (ditrm) { if (ditrm->remote) break; /* If ditrm->touched_title is 0, then * ditrm->orig_title should be NULL, * but check it to prevent any leak. */ if (!ditrm->orig_title && !ditrm->touched_title) ditrm->orig_title = get_window_title( ditrm->title_codepage); ditrm->touched_title = 1; } /* TODO: Is it really possible to get here with * ditrm == NULL, and which charset would then * be most appropriate? */ set_window_title(text + 1, ditrm ? ditrm->title_codepage : get_cp_index("US-ASCII")); break; case TERM_FN_RESIZE: if (ditrm && ditrm->remote) break; resize_terminal_from_str(text + 1); break; case TERM_FN_TITLE_CODEPAGE: if (ditrm) { int cp = get_cp_index(text + 1); /* If the master sends the name of an * unrecognized charset, assume only * that it's ASCII compatible. */ if (cp == -1) cp = get_cp_index("US-ASCII"); ditrm->title_codepage = cp; } break; } }
/** Convert a STRING XTextProperty to a string in the specified codepage. * * @return the string that the caller must free with mem_free(), * or NULL on error. */ static unsigned char * xprop_to_string(Display *display, const XTextProperty *text_prop, int to_cp) { int from_cp; char **list = NULL; int count = 0; struct conv_table *convert_table; unsigned char *ret = NULL; /* <X11/Xlib.h> defines X_HAVE_UTF8_STRING if * Xutf8TextPropertyToTextList is available. * * The X...TextPropertyToTextList functions return a negative * error code, or Success=0, or the number of unconvertible * characters. Use the result even if some characters were * unconvertible, because convert_string() can be lossy too, * and it seems better to restore an approximation of the * original title than to restore a default title that may be * entirely different. */ #if defined(CONFIG_UTF8) && defined(X_HAVE_UTF8_STRING) from_cp = get_cp_index((const unsigned char *)"UTF-8"); if (Xutf8TextPropertyToTextList(display, text_prop, &list, &count) < 0) return NULL; #else /* !defined(X_HAVE_UTF8_STRING) || !defined(CONFIG_UTF8) */ from_cp = get_cp_index((const unsigned char *)"System"); if (XmbTextPropertyToTextList(display, text_prop, &list, &count) < 0) return NULL; #endif /* !defined(X_HAVE_UTF8_STRING) || !defined(CONFIG_UTF8) */ convert_table = get_translation_table(from_cp, to_cp); if (count >= 1 && convert_table) ret = convert_string(convert_table, (unsigned char *)list[0], strlen((const char *)list[0]), to_cp, CSM_NONE, NULL, NULL, NULL); XFreeStringList(list); return ret; }
/* @bookmark_class.setProperty */ static JSBool bookmark_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { struct bookmark *bookmark; jsid tmp; unsigned char *title = NULL; unsigned char *url = NULL; int ok; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &bookmark_class, NULL)) return JS_FALSE; bookmark = JS_GetInstancePrivate(ctx, obj, (JSClass *) &bookmark_class, NULL); if (!bookmark) return JS_FALSE; if (!JSID_IS_INT(id)) return JS_FALSE; switch (JSID_TO_INT(id)) { case BOOKMARK_TITLE: if (!JS_ValueToId(ctx, *vp, &tmp)) return JS_FALSE; if (!jsval_to_bookmark_string(ctx, tmp, &title)) return JS_FALSE; break; case BOOKMARK_URL: if (!JS_ValueToId(ctx, *vp, &tmp)) return JS_FALSE; if (!jsval_to_bookmark_string(ctx, tmp, &url)) return JS_FALSE; break; default: /* Unrecognized integer property ID; someone is using * the object as an array. SMJS builtin classes (e.g. * js_RegExpClass) just return JS_TRUE in this case. * Do the same here. */ return JS_TRUE; } ok = update_bookmark(bookmark, get_cp_index("UTF-8"), title, url); mem_free_if(title); mem_free_if(url); return ok ? JS_TRUE : JS_FALSE; }
void set_language(int l) { int i; unsigned char *cp; for (i = 0; i < T__N_TEXTS; i++) if (translations[l].t[i].code != i) { internal("Bad table for language %s. Run script synclang.", translations[l].t[T__LANGUAGE].name); return; } current_language = l; cp = cast_uchar translations[l].t[T__CHAR_SET].name; i = get_cp_index(cp); if (i == -1) { internal("Unknown charset for language %s.", translations[l].t[T__LANGUAGE].name); i = 0; } current_lang_charset = i; }
static void free_itrm(struct itrm *itrm) { if (!itrm) return; if (!itrm->remote) { if (itrm->orig_title && *itrm->orig_title) { set_window_title(itrm->orig_title, itrm->title_codepage); } else if (itrm->touched_title) { /* Set the window title to the value of $TERM if X11 * wasn't compiled in. Should hopefully make at least * half the users happy. (debian bug #312955) */ unsigned char title[MAX_TERM_LEN]; get_terminal_name(title); if (*title) set_window_title(title, get_cp_index("US-ASCII")); } unhandle_terminal_resize(itrm->in.ctl); #ifdef CONFIG_MOUSE disable_mouse(); #endif send_done_sequence(itrm->out.std, itrm->altscreen); tcsetattr(itrm->in.ctl, TCSANOW, &itrm->t); } mem_free_set(&itrm->orig_title, NULL); /* elinks -remote may not have a valid stdin if not run from a tty (bug 938) */ if (!itrm->remote || itrm->in.std >= 0) clear_handlers(itrm->in.std); clear_handlers(itrm->in.sock); clear_handlers(itrm->out.std); clear_handlers(itrm->out.sock); kill_timer(&itrm->timer); if (itrm == ditrm) ditrm = NULL; mem_free_if(itrm->out.queue.data); mem_free_if(itrm->in.queue.data); mem_free(itrm); }
/* initiate connection with X server */ static unsigned char * x_init_driver(unsigned char *param, unsigned char *display) { XGCValues gcv; XSetWindowAttributes win_attr; XVisualInfo vinfo; int misordered=-1; n_wins=0; #if defined(HAVE_SETLOCALE) && defined(LC_ALL) setlocale(LC_ALL,""); #endif #ifdef X_DEBUG { unsigned char txt[256]; sprintf(txt,"x_init_driver(%s, %s)\n",param, display); MESSAGE(txt); } #endif x_input_encoding=-1; #if defined(HAVE_NL_LANGINFO) && defined(HAVE_LANGINFO_H) && defined(CODESET) { unsigned char *cp; cp=nl_langinfo(CODESET); x_input_encoding=get_cp_index(cp); } #endif if (x_input_encoding<0)x_driver.flags|=GD_NEED_CODEPAGE; if (!display||!(*display))display=0; /* X documentation says on XOpenDisplay(display_name) : display_name Specifies the hardware display name, which determines the dis- play and communications domain to be used. On a POSIX-confor- mant system, if the display_name is NULL, it defaults to the value of the DISPLAY environment variable. But OS/2 has problems when display_name is NULL ... */ if (!display)display=getenv("DISPLAY"); #ifndef __linux__ /* on Linux, do not assume XWINDOW present if $DISPLAY is not set --- rather open links on svgalib or framebuffer console */ if (!display)display=":0.0"; /* needed for MacOS X */ #endif x_display=XOpenDisplay(display); if (!x_display) { unsigned char *err=init_str(); int l=0; add_to_str(&err,&l,"Can't open display \""); add_to_str(&err,&l,display?display:(unsigned char *)"(null)"); add_to_str(&err,&l,"\"\n"); return err; } x_hash_table_init(); x_bitmap_bit_order=BitmapBitOrder(x_display); x_fd=XConnectionNumber(x_display); x_screen=DefaultScreen(x_display); x_display_height=DisplayHeight(x_display,x_screen); x_display_width=DisplayWidth(x_display,x_screen); x_root_window=RootWindow(x_display,x_screen); x_default_window_width=x_display_width-50; x_default_window_height=x_display_height-50; x_driver_param=NULL; if (param) { char *p, *e, *f; int w,h; x_driver_param=stracpy(param); for (p=x_driver_param;(*p)&&(*p)!='x'&&(*p)!='X';p++); if (!(*p))goto done; *p=0; w=strtoul(x_driver_param,&e,10); h=strtoul(p+1,&f,10); if (!(*e)&&!(*f)&&w&&h){x_default_window_width=w;x_default_window_height=h;} *p='x'; done:; } /* find best visual */ { #define DEPTHS 5 #define CLASSES 2 int depths[DEPTHS]={24, 16, 15, 8, 4}; int classes[CLASSES]={TrueColor, PseudoColor}; /* FIXME: dodelat DirectColor */ int a,b; for (a=0;a<DEPTHS;a++) for (b=0;b<CLASSES;b++) { if (XMatchVisualInfo(x_display, x_screen,depths[a],classes[b], &vinfo)) { x_default_visual=vinfo.visual; x_depth=vinfo.depth; /* determine bytes per pixel */ { XPixmapFormatValues *pfm; int n,i; pfm=XListPixmapFormats(x_display,&n); for (i=0;i<n;i++) if (pfm[i].depth==x_depth) { x_bitmap_bpp=pfm[i].bits_per_pixel<8?1:((pfm[i].bits_per_pixel)>>3); x_bitmap_scanline_pad=(pfm[i].scanline_pad)>>3; XFree(pfm); goto bytes_per_pixel_found; } if(n) XFree(pfm); continue; } bytes_per_pixel_found: /* test misordered flag */ switch(x_depth) { case 4: case 8: if (x_bitmap_bpp!=1)break; if (vinfo.red_mask>=vinfo.green_mask&&vinfo.green_mask>=vinfo.blue_mask) { misordered=0; goto visual_found; } break; case 15: case 16: if (x_bitmap_bpp!=2)break; if (x_bitmap_bit_order==MSBFirst&&vinfo.red_mask>vinfo.green_mask&&vinfo.green_mask>vinfo.blue_mask) { misordered=256; goto visual_found; } if (x_bitmap_bit_order==MSBFirst)break; if (vinfo.red_mask>vinfo.green_mask&&vinfo.green_mask>vinfo.blue_mask) { misordered=0; goto visual_found; } break; case 24: if (x_bitmap_bpp!=3&&x_bitmap_bpp!=4) break; if (vinfo.red_mask<vinfo.green_mask&&vinfo.green_mask<vinfo.blue_mask) { misordered=256; goto visual_found; } if (x_bitmap_bit_order==MSBFirst&&vinfo.red_mask>vinfo.green_mask&&vinfo.green_mask>vinfo.blue_mask) { misordered=512; goto visual_found; } if (vinfo.red_mask>vinfo.green_mask&&vinfo.green_mask>vinfo.blue_mask) { misordered=0; goto visual_found; } break; } } }
/** Set screen_driver.opt according to screen_driver.type and @a term_spec. * Other members of @a *driver need not have been initialized. * * If you modify anything here, check whether option descriptions * should be updated. */ static void set_screen_driver_opt(struct screen_driver *driver, struct option *term_spec) { const int cp = get_opt_codepage_tree(term_spec, (const unsigned char *)"charset", NULL); int utf8_io = get_opt_bool_tree(term_spec, (const unsigned char *)"utf_8_io", NULL); /* Copy all the original options from constants, so that this * function need not carefully restore options one by one. */ copy_struct(&driver->opt, screen_driver_opts[driver->type]); #ifdef CONFIG_COMBINE driver->opt.combine = get_opt_bool_tree(term_spec, (const unsigned char *)"combine", NULL); #endif /* CONFIG_COMBINE */ #ifdef CONFIG_UTF8 /* Force UTF-8 I/O if the UTF-8 charset is selected. Various * places assume that the terminal's charset is unibyte if * UTF-8 I/O is disabled. (bug 827) */ if (is_cp_utf8(cp)) { driver->opt.utf8_cp = 1; utf8_io = 1; } else { driver->opt.utf8_cp = 0; } #endif /* CONFIG_UTF8 */ driver->opt.color_mode = get_opt_int_tree(term_spec, (const unsigned char *)"colors", NULL); driver->opt.transparent = get_opt_bool_tree(term_spec, (const unsigned char *)"transparency", NULL); if (get_opt_bool_tree(term_spec, (const unsigned char *)"italic", NULL)) { driver->opt.italic = italic_seqs; } else { driver->opt.italic = NULL; } if (get_opt_bool_tree(term_spec, (const unsigned char *)"underline", NULL)) { driver->opt.underline = underline_seqs; } else { driver->opt.underline = NULL; } if (utf8_io) { driver->opt.charsets[0] = cp; /* When we're using UTF-8 I/O, we never need to switch * charsets or fonts for drawing frames, because the * characters encoded in UTF-8 are already unambiguous. */ driver->opt.frame_seqs = NULL; if (driver->type == TERM_LINUX || driver->type == TERM_FBTERM) { if (get_opt_bool_tree(term_spec, (const unsigned char *)"restrict_852", NULL)) driver->opt.frame = frame_restrict; driver->opt.charsets[1] = get_cp_index((const unsigned char *)"cp437"); } else if (driver->type == TERM_FREEBSD) { driver->opt.frame = frame_freebsd_u; driver->opt.charsets[1] = get_cp_index((const unsigned char *)"cp437"); } else if (driver->type == TERM_VT100) { driver->opt.frame = frame_vt100_u; driver->opt.charsets[1] = get_cp_index((const unsigned char *)"cp437"); } else if (driver->type == TERM_KOI8) { driver->opt.charsets[1] = get_cp_index((const unsigned char *)"koi8-r"); } else { #ifdef CONFIG_UTF8 /* Don't let driver->opt.charsets[1] become * UTF-8, because it is passed to cp2u(), * which supports only unibyte characters. */ if (driver->opt.utf8_cp) driver->opt.charsets[1] = get_cp_index((const unsigned char *)"US-ASCII"); else #endif /* CONFIG_UTF8 */ driver->opt.charsets[1] = driver->opt.charsets[0]; } } else { /* !utf8_io */ driver->opt.charsets[0] = -1; if (driver->type == TERM_LINUX) { if (get_opt_bool_tree(term_spec, (const unsigned char *)"restrict_852", NULL)) driver->opt.frame = frame_restrict; if (get_opt_bool_tree(term_spec, (const unsigned char *)"m11_hack", NULL)) driver->opt.frame_seqs = m11_hack_frame_seqs; } else if (driver->type == TERM_FREEBSD) { if (get_opt_bool_tree(term_spec, (const unsigned char *)"m11_hack", NULL)) driver->opt.frame_seqs = m11_hack_frame_seqs; } else if (driver->type == TERM_VT100) { driver->opt.frame = frame_vt100; } } /* !utf8_io */ }
/** Construct the struct itrm of this process, make ::ditrm point to it, * set up select() handlers, and send the initial interlink packet. * * The first five parameters are file descriptors that this function * saves in submembers of struct itrm, and for which this function may * set select() handlers. Please see the definitions of struct * itrm_in and struct itrm_out for further explanations. * * @param std_in itrm_in.std: read tty device (or pipe) * @param std_out itrm_out.std: write tty device (or pipe) * @param sock_in itrm_in.sock * - If master: == @a std_out (masterhood flag) * - If slave: read socket from master * @param sock_out itrm_out.sock * - If master: write pipe to same process * - If slave: write socket to master * @param ctl_in itrm_in.ctl: control tty device * * The remaining three parameters control the initial interlink packet. * * @param init_string A string to be passed to the master process. Need * not be null-terminated. If @a remote == 0, this is * a URI. Otherwise, this is a remote command. * @param init_len The length of init_string, in bytes. * @param remote = 0 if asking the master to start a new session * and display it via this process. Otherwise, * enum ::remote_session_flags. */ void handle_trm(int std_in, int std_out, int sock_in, int sock_out, int ctl_in, void *init_string, int init_len, int remote) { struct itrm *itrm; struct terminal_info info; struct interlink_event_size *size = &info.event.info.size; unsigned char *ts; memset(&info, 0, sizeof(info)); get_terminal_size(ctl_in, &size->width, &size->height); info.event.ev = EVENT_INIT; info.system_env = get_system_env(); info.length = init_len; if (remote) { info.session_info = remote; info.magic = INTERLINK_REMOTE_MAGIC; } else { info.session_info = get_cmd_opt_int("base-session"); info.magic = INTERLINK_NORMAL_MAGIC; } itrm = mem_calloc(1, sizeof(*itrm)); if (!itrm) return; itrm->in.queue.data = mem_calloc(1, ITRM_IN_QUEUE_SIZE); if (!itrm->in.queue.data) { mem_free(itrm); return; } ditrm = itrm; itrm->in.std = std_in; itrm->out.std = std_out; itrm->in.sock = sock_in; itrm->out.sock = sock_out; itrm->in.ctl = ctl_in; itrm->timer = TIMER_ID_UNDEF; itrm->remote = !!remote; /* If the master does not tell which charset it's using in * this terminal, assume it's some ISO 8859. Because that's * what older versions of ELinks did. */ itrm->title_codepage = get_cp_index("ISO-8859-1"); /* FIXME: Combination altscreen + xwin does not work as it should, * mouse clicks are reportedly partially ignored. */ if (info.system_env & (ENV_SCREEN | ENV_XWIN)) itrm->altscreen = 1; if (!remote) { if (ctl_in >= 0) setraw(itrm, 1); send_init_sequence(std_out, itrm->altscreen); handle_terminal_resize(ctl_in, resize_terminal); #ifdef CONFIG_MOUSE enable_mouse(); #endif handle_itrm_stdin(itrm); } else { /* elinks -remote may not have a valid stdin if not run from a tty (bug 938) */ if (std_in >= 0) handle_itrm_stdin(itrm); } if (sock_in != std_out) set_handlers(sock_in, (select_handler_T) in_sock, NULL, (select_handler_T) free_itrm, itrm); get_terminal_name(info.name); ts = get_cwd(); if (ts) { memcpy(info.cwd, ts, int_min(strlen(ts), MAX_CWD_LEN)); mem_free(ts); } itrm_queue_event(itrm, (char *) &info, TERMINAL_INFO_SIZE); itrm_queue_event(itrm, (char *) init_string, init_len); }
/* To reduce redundant error handling code [calls to abort_connection()] * most of the function is build around conditions that will assign the error * code to @state if anything goes wrong. The rest of the function will then just * do the necessary cleanups. If all works out we end up with @state being S_OK * resulting in a cache entry being created with the fragment data generated by * either reading the file content or listing a directory. */ void file_protocol_handler(struct connection *connection) { unsigned char *redirect_location = NULL; struct string page, name; struct connection_state state; int set_dir_content_type = 0; if (get_cmd_opt_bool((const unsigned char *)"anonymous")) { if (strcmp((const char *)connection->uri->string, "file:///dev/stdin") || isatty(STDIN_FILENO)) { abort_connection(connection, connection_state(S_FILE_ANONYMOUS)); return; } } #ifdef CONFIG_CGI if (!execute_cgi(connection)) return; #endif /* CONFIG_CGI */ /* Treat /dev/stdin in special way */ if (!strcmp((const char *)connection->uri->string, "file:///dev/stdin")) { int fd = open("/dev/stdin", O_RDONLY); if (fd == -1) { abort_connection(connection, connection_state(-errno)); return; } set_nonblocking_fd(fd); if (!init_http_connection_info(connection, 1, 0, 1)) { abort_connection(connection, connection_state(S_OUT_OF_MEM)); close(fd); return; } connection->socket->fd = fd; connection->data_socket->fd = -1; read_from_stdin(connection); return; } /* This function works on already simplified file-scheme URI pre-chewed * by transform_file_url(). By now, the function contains no hostname * part anymore, possibly relative path is converted to an absolute one * and uri->data is just the final path to file/dir we should try to * show. */ if (!init_string(&name) || !add_uri_to_string(&name, connection->uri, URI_PATH)) { done_string(&name); abort_connection(connection, connection_state(S_OUT_OF_MEM)); return; } decode_uri_string(&name); /* In Win32, file_is_dir seems to always return 0 if the name * ends with a directory separator. */ if ((name.length > 0 && dir_sep(name.source[name.length - 1])) || file_is_dir(name.source)) { /* In order for global history and directory listing to * function properly the directory url must end with a * directory separator. */ if (name.source[0] && !dir_sep(name.source[name.length - 1])) { redirect_location = (unsigned char *)STRING_DIR_SEP; state = connection_state(S_OK); } else { state = list_directory(connection, name.source, &page); set_dir_content_type = 1; } } else { state = read_encoded_file(&name, &page); /* FIXME: If state is now S_ENCODE_ERROR we should try loading * the file undecoded. --jonas */ } done_string(&name); if (is_in_state(state, S_OK)) { struct cache_entry *cached; /* Try to add fragment data to the connection cache if either * file reading or directory listing worked out ok. */ cached = connection->cached = get_cache_entry(connection->uri); if (!connection->cached) { if (!redirect_location) done_string(&page); state = connection_state(S_OUT_OF_MEM); } else if (redirect_location) { if (!redirect_cache(cached, redirect_location, 1, 0)) state = connection_state(S_OUT_OF_MEM); } else { add_fragment(cached, 0, page.source, page.length); connection->from += page.length; if (!cached->head && set_dir_content_type) { unsigned char *head; /* If the system charset somehow * changes after the directory listing * has been generated, it should be * parsed with the original charset. */ head = straconcat((const unsigned char *)"\r\nContent-Type: text/html; charset=", get_cp_mime_name(get_cp_index((const unsigned char *)"System")), "\r\n", (unsigned char *) NULL); /* Not so gracefully handle failed memory * allocation. */ if (!head) state = connection_state(S_OUT_OF_MEM); /* Setup directory listing for viewing. */ mem_free_set(&cached->head, head); } done_string(&page); } } abort_connection(connection, state); }