1 /* Internal "mailto", "telnet", "tn3270" and misc. protocol implementation */
16 #include "bfu/dialog.h"
17 #include "config/options.h"
18 #include "intl/gettext/libintl.h"
19 #include "main/module.h"
20 #include "osdep/osdep.h"
21 #include "protocol/uri.h"
22 #include "protocol/user.h"
23 #include "session/download.h"
24 #include "session/session.h"
25 #include "terminal/terminal.h"
26 #include "terminal/window.h"
27 #include "util/conv.h"
28 #include "util/file.h"
29 #include "util/memory.h"
30 #include "util/string.h"
33 static union option_info user_protocol_options
[] = {
34 INIT_OPT_TREE("protocol", N_("User protocols"),
35 "user", OPT_AUTOCREATE
,
36 N_("User protocols. Options in this tree specify external "
37 "handlers for the appropriate protocols. Ie. "
38 "protocol.user.mailto.unix.")),
40 /* FIXME: Poorly designed options structure. Ought to be able to specify
41 * need_slashes, free_form and similar options as well :-(. --pasky */
43 /* Basically, it looks like protocol.user.mailto.win32 = "blah" */
45 INIT_OPT_TREE("protocol.user", NULL
,
46 "_template_", OPT_AUTOCREATE
,
47 N_("Handler (external program) for this protocol. Name the "
48 "options in this tree after your system (ie. unix, "
51 INIT_OPT_STRING("protocol.user._template_", NULL
,
53 N_("Handler (external program) for this protocol and system.\n"
54 "%f in the string means file name to include form data from\n"
55 "%h in the string means hostname (or email address)\n"
56 "%p in the string means port\n"
57 "%d in the string means path (everything after the port)\n"
58 "%s in the string means subject (?subject=<this>)\n"
59 "%u in the string means the whole URL")),
61 #define INIT_OPT_USER_PROTOCOL(scheme, system, cmd) \
62 INIT_OPT_STRING("protocol.user." scheme, NULL, system, 0, cmd, NULL)
65 INIT_OPT_USER_PROTOCOL("gopher", "unix", DEFAULT_AC_OPT_GOPHER
),
66 INIT_OPT_USER_PROTOCOL("gopher", "unix-xwin", DEFAULT_AC_OPT_GOPHER
),
68 INIT_OPT_USER_PROTOCOL("irc", "unix", DEFAULT_AC_OPT_IRC
),
69 INIT_OPT_USER_PROTOCOL("irc", "unix-xwin", DEFAULT_AC_OPT_IRC
),
70 INIT_OPT_USER_PROTOCOL("mailto", "unix", DEFAULT_AC_OPT_MAILTO
),
71 INIT_OPT_USER_PROTOCOL("mailto", "unix-xwin", DEFAULT_AC_OPT_MAILTO
),
73 INIT_OPT_USER_PROTOCOL("news", "unix", DEFAULT_AC_OPT_NEWS
),
74 INIT_OPT_USER_PROTOCOL("news", "unix-xwin", DEFAULT_AC_OPT_NEWS
),
76 INIT_OPT_USER_PROTOCOL("telnet", "unix", DEFAULT_AC_OPT_TELNET
),
77 INIT_OPT_USER_PROTOCOL("telnet", "unix-xwin", DEFAULT_AC_OPT_TELNET
),
78 INIT_OPT_USER_PROTOCOL("tn3270", "unix", DEFAULT_AC_OPT_TN3270
),
79 INIT_OPT_USER_PROTOCOL("tn3270", "unix-xwin", DEFAULT_AC_OPT_TN3270
),
84 struct module user_protocol_module
= struct_module(
85 /* name: */ N_("User protocols"),
86 /* options: */ user_protocol_options
,
88 /* submodules: */ NULL
,
96 get_user_program(struct terminal
*term
, unsigned char *progid
, int progidlen
)
99 int xwin
= term
? term
->environment
& ENV_XWIN
: 0;
102 if (!init_string(&name
)) return NULL
;
104 add_to_string(&name
, "protocol.user.");
106 /* Now add lowercased progid part. Delicious. */
107 add_bytes_to_string(&name
, progid
, progidlen
);
108 convert_to_lowercase_locale_indep(&name
.source
[sizeof("protocol.user.") - 1], progidlen
);
110 add_char_to_string(&name
, '.');
111 add_to_string(&name
, get_system_str(xwin
));
113 opt
= get_opt_rec_real(config_options
, name
.source
);
116 return (unsigned char *) (opt
? opt
->value
.string
: NULL
);
120 static unsigned char *
121 subst_cmd(unsigned char *cmd
, struct uri
*uri
, unsigned char *subj
,
122 unsigned char *formfile
)
124 struct string string
;
126 if (!init_string(&string
)) return NULL
;
131 for (p
= 0; cmd
[p
] && cmd
[p
] != '%'; p
++);
133 add_bytes_to_string(&string
, cmd
, p
);
136 if (*cmd
!= '%') break;
139 /* TODO: Decode URI fragments before adding them. --jonas */
143 unsigned char *url
= struri(uri
);
144 int length
= get_real_uri_length(uri
);
146 add_shell_safe_to_string(&string
, url
, length
);
150 /* TODO For some user protocols it would be
151 * better if substitution of each uri
152 * field was completely configurable. Now
153 * @host contains both the uri username
154 * field, (password field) and hostname
155 * field because it is useful for mailto
156 * protocol handling. */
157 /* It would break a lot of configurations so I
158 * don't know. --jonas */
159 if (uri
->userlen
&& uri
->hostlen
) {
160 int hostlen
= uri
->host
+ uri
->hostlen
- uri
->user
;
162 add_shell_safe_to_string(&string
, uri
->user
,
164 } else if (uri
->host
) {
165 add_shell_safe_to_string(&string
, uri
->host
,
171 add_shell_safe_to_string(&string
, uri
->port
,
176 add_shell_safe_to_string(&string
, uri
->data
,
181 add_shell_safe_to_string(&string
, subj
,
186 add_to_string(&string
, formfile
);
189 add_bytes_to_string(&string
, cmd
- 1, 2);
195 return string
.source
;
198 /* Stay silent about complete RFC 2368 support or do it yourself! ;-).
200 static unsigned char *
201 get_subject_from_query(unsigned char *query
)
203 unsigned char *subject
;
205 if (strncmp(query
, "subject=", 8)) {
206 subject
= strstr((const char *)query
, "&subject=");
207 if (!subject
) return NULL
;
213 /* Return subject until next '&'-value or end of string */
214 return memacpy(subject
, strcspn(subject
, "&"));
217 static unsigned char *
218 save_form_data_to_file(struct uri
*uri
)
220 unsigned char *filename
= get_tempdir_filename("elinks-XXXXXX");
224 unsigned char *formdata
;
226 if (!filename
) return NULL
;
228 fd
= safe_mkstemp(filename
);
234 if (!uri
->post
) return filename
;
236 /* Jump the content type */
237 formdata
= strchr((const char *)uri
->post
, '\n');
238 formdata
= formdata
? formdata
+ 1 : uri
->post
;
239 len
= strlen(formdata
);
240 if (len
== 0) return filename
;
242 fp
= fdopen(fd
, "w");
252 nmemb
= fwrite(formdata
, len
, 1, fp
);
265 user_protocol_handler(struct session
*ses
, struct uri
*uri
)
267 unsigned char *subj
= NULL
, *prog
;
268 unsigned char *filename
;
270 prog
= get_user_program(ses
->tab
->term
, struri(uri
), uri
->protocollen
);
271 if (!prog
|| !*prog
) {
272 unsigned char *protocol
= memacpy(struri(uri
), uri
->protocollen
);
274 /* Shouldn't ever happen, but be paranoid. */
275 /* Happens when you're in X11 and you've no handler for it. */
276 info_box(ses
->tab
->term
, MSGBOX_FREE_TEXT
,
277 N_("No program"), ALIGN_CENTER
,
278 msg_text(ses
->tab
->term
,
279 N_("No program specified for protocol %s."),
280 empty_string_or_(protocol
)));
282 mem_free_if(protocol
);
286 if (uri
->data
&& uri
->datalen
) {
287 /* Some mailto specific stuff follows... */
288 unsigned char *query
= get_uri_string(uri
, URI_QUERY
);
291 subj
= get_subject_from_query(query
);
293 if (subj
) decode_uri(subj
);
297 filename
= save_form_data_to_file(uri
);
299 prog
= subst_cmd(prog
, uri
, subj
, filename
);
302 unsigned char *delete_
= empty_string_or_(filename
);
304 exec_on_terminal(ses
->tab
->term
, prog
, delete_
, TERM_EXEC_FG
);
307 } else if (filename
) {
311 mem_free_if(filename
);