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 struct 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\n"
37 "handlers for the appropriate protocols. Ie.\n"
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\n"
48 "options in this tree after your system (ie. unix, unix-xwin).")),
50 INIT_OPT_STRING("protocol.user._template_", NULL
,
52 N_("Handler (external program) for this protocol and system.\n"
53 "%f in the string means file name to include form data from\n"
54 "%h in the string means hostname (or email address)\n"
55 "%p in the string means port\n"
56 "%d in the string means path (everything after the port)\n"
57 "%s in the string means subject (?subject=<this>)\n"
58 "%u in the string means the whole URL")),
60 #define INIT_OPT_USER_PROTOCOL(scheme, system, cmd) \
61 INIT_OPT_STRING("protocol.user." scheme, NULL, system, 0, cmd, NULL)
64 INIT_OPT_USER_PROTOCOL("gopher", "unix", DEFAULT_AC_OPT_GOPHER
),
65 INIT_OPT_USER_PROTOCOL("gopher", "unix-xwin", DEFAULT_AC_OPT_GOPHER
),
67 INIT_OPT_USER_PROTOCOL("irc", "unix", DEFAULT_AC_OPT_IRC
),
68 INIT_OPT_USER_PROTOCOL("irc", "unix-xwin", DEFAULT_AC_OPT_IRC
),
69 INIT_OPT_USER_PROTOCOL("mailto", "unix", DEFAULT_AC_OPT_MAILTO
),
70 INIT_OPT_USER_PROTOCOL("mailto", "unix-xwin", DEFAULT_AC_OPT_MAILTO
),
72 INIT_OPT_USER_PROTOCOL("news", "unix", DEFAULT_AC_OPT_NEWS
),
73 INIT_OPT_USER_PROTOCOL("news", "unix-xwin", DEFAULT_AC_OPT_NEWS
),
75 INIT_OPT_USER_PROTOCOL("telnet", "unix", DEFAULT_AC_OPT_TELNET
),
76 INIT_OPT_USER_PROTOCOL("telnet", "unix-xwin", DEFAULT_AC_OPT_TELNET
),
77 INIT_OPT_USER_PROTOCOL("tn3270", "unix", DEFAULT_AC_OPT_TN3270
),
78 INIT_OPT_USER_PROTOCOL("tn3270", "unix-xwin", DEFAULT_AC_OPT_TN3270
),
83 struct module user_protocol_module
= struct_module(
84 /* name: */ N_("User protocols"),
85 /* options: */ user_protocol_options
,
87 /* submodules: */ NULL
,
95 get_user_program(struct terminal
*term
, unsigned char *progid
, int progidlen
)
98 int xwin
= term
? term
->environment
& ENV_XWIN
: 0;
101 if (!init_string(&name
)) return NULL
;
103 add_to_string(&name
, "protocol.user.");
105 /* Now add lowercased progid part. Delicious. */
106 add_bytes_to_string(&name
, progid
, progidlen
);
107 convert_to_lowercase(&name
.source
[sizeof("protocol.user.") - 1], progidlen
);
109 add_char_to_string(&name
, '.');
110 add_to_string(&name
, get_system_str(xwin
));
112 opt
= get_opt_rec_real(config_options
, name
.source
);
115 return (unsigned char *) (opt
? opt
->value
.string
: NULL
);
119 static unsigned char *
120 subst_cmd(unsigned char *cmd
, struct uri
*uri
, unsigned char *subj
,
121 unsigned char *formfile
)
123 struct string string
;
125 if (!init_string(&string
)) return NULL
;
130 for (p
= 0; cmd
[p
] && cmd
[p
] != '%'; p
++);
132 add_bytes_to_string(&string
, cmd
, p
);
135 if (*cmd
!= '%') break;
138 /* TODO: Decode URI fragments before adding them. --jonas */
142 unsigned char *url
= struri(uri
);
143 int length
= get_real_uri_length(uri
);
145 add_shell_safe_to_string(&string
, url
, length
);
149 /* TODO For some user protocols it would be
150 * better if substitution of each uri
151 * field was completely configurable. Now
152 * @host contains both the uri username
153 * field, (password field) and hostname
154 * field because it is useful for mailto
155 * protocol handling. */
156 /* It would break a lot of configurations so I
157 * don't know. --jonas */
158 if (uri
->userlen
&& uri
->hostlen
) {
159 int hostlen
= uri
->host
+ uri
->hostlen
- uri
->user
;
161 add_shell_safe_to_string(&string
, uri
->user
,
163 } else if (uri
->host
) {
164 add_shell_safe_to_string(&string
, uri
->host
,
170 add_shell_safe_to_string(&string
, uri
->port
,
175 add_shell_safe_to_string(&string
, uri
->data
,
180 add_shell_safe_to_string(&string
, subj
,
185 add_to_string(&string
, formfile
);
188 add_bytes_to_string(&string
, cmd
- 1, 2);
194 return string
.source
;
197 /* Stay silent about complete RFC 2368 support or do it yourself! ;-).
199 static unsigned char *
200 get_subject_from_query(unsigned char *query
)
202 unsigned char *subject
;
204 if (strncmp(query
, "subject=", 8)) {
205 subject
= strstr(query
, "&subject=");
206 if (!subject
) return NULL
;
212 /* Return subject until next '&'-value or end of string */
213 return memacpy(subject
, strcspn(subject
, "&"));
216 static unsigned char *
217 save_form_data_to_file(struct uri
*uri
)
219 unsigned char *filename
= get_tempdir_filename("elinks-XXXXXX");
223 if (!filename
) return NULL
;
225 formfd
= safe_mkstemp(filename
);
231 formfile
= fdopen(formfd
, "w");
239 /* Jump the content type */
240 unsigned char *formdata
= strchr(uri
->post
, '\n');
242 formdata
= formdata
? formdata
+ 1 : uri
->post
;
243 fwrite(formdata
, strlen(formdata
), 1, formfile
);
251 user_protocol_handler(struct session
*ses
, struct uri
*uri
)
253 unsigned char *subj
= NULL
, *prog
;
254 unsigned char *formfilename
;
256 prog
= get_user_program(ses
->tab
->term
, struri(uri
), uri
->protocollen
);
257 if (!prog
|| !*prog
) {
258 unsigned char *protocol
= memacpy(struri(uri
), uri
->protocollen
);
260 /* Shouldn't ever happen, but be paranoid. */
261 /* Happens when you're in X11 and you've no handler for it. */
262 info_box(ses
->tab
->term
, MSGBOX_FREE_TEXT
,
263 N_("No program"), ALIGN_CENTER
,
264 msg_text(ses
->tab
->term
,
265 N_("No program specified for protocol %s."),
266 empty_string_or_(protocol
)));
268 mem_free_if(protocol
);
272 if (uri
->data
&& uri
->datalen
) {
273 /* Some mailto specific stuff follows... */
274 unsigned char *query
= get_uri_string(uri
, URI_QUERY
);
277 subj
= get_subject_from_query(query
);
279 if (subj
) decode_uri(subj
);
283 formfilename
= save_form_data_to_file(uri
);
285 prog
= subst_cmd(prog
, uri
, subj
, formfilename
);
288 unsigned char *delete = empty_string_or_(formfilename
);
290 exec_on_terminal(ses
->tab
->term
, prog
, delete, 1);
293 } else if (formfilename
) {
294 unlink(formfilename
);
297 mem_free_if(formfilename
);