blob: f62e2f53a79527fc48a86b51088dd003fbf038d2 [file] [log] [blame]
dkegel@google.comf20da1f2009-06-30 19:16:32 +00001#!/bin/bash
2#---------------------------------------------
3# xdg-email
4#
5# Utility script to open the users favorite email program, using the
6# RFC 2368 mailto: URI spec
7#
8# Refer to the usage() function below for usage.
9#
10# Copyright 2006, Kevin Krammer <kevin.krammer@gmx.at>
11# Copyright 2006, Jeremy White <jwhite@codeweavers.com>
12#
13# LICENSE:
14#
15# Permission is hereby granted, free of charge, to any person obtaining a
16# copy of this software and associated documentation files (the "Software"),
17# to deal in the Software without restriction, including without limitation
18# the rights to use, copy, modify, merge, publish, distribute, sublicense,
19# and/or sell copies of the Software, and to permit persons to whom the
20# Software is furnished to do so, subject to the following conditions:
21#
22# The above copyright notice and this permission notice shall be included
23# in all copies or substantial portions of the Software.
24#
25# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
31# OTHER DEALINGS IN THE SOFTWARE.
32#
33#---------------------------------------------
34
35manualpage()
36{
37cat << _MANUALPAGE
38Name
39
40xdg-email - command line tool for sending mail using the user's preferred
41e-mail composer
42
43Synopsis
44
45xdg-email [--utf8] [--cc address] [--bcc address] [--subject text] [--body text
46] [--attach file] [ mailto-uri | address(es) ]
47
48xdg-email { --help | --manual | --version }
49
50Description
51
52xdg-email opens the user's preferred e-mail composer in order to send a mail to
53address(es) or mailto-uri. RFC2368 defines mailto: URIs. xdg-email limits
54support to, cc, subject and body fields in mailto-uri, all other fields are
55silently ignored. address(es) must follow the syntax of RFC822. Multiple
56addresses may be provided as separate arguments.
57
58All information provided on the command line is used to prefill corresponding
59fields in the user's e-mail composer. The user will have the opportunity to
60change any of this information before actually sending the e-mail.
61
62xdg-email is for use inside a desktop session only. It is not recommended to
63use xdg-email as root.
64
65See http://portland.freedesktop.org/EmailConfig for information on how the user
66can change the e-mail composer that is used.
67
68Options
69
70--utf8
71 Indicates that all command line options that follow are in utf8. Without
72 this option, command line options are expected to be encoded according to
73 locale. If the locale already specifies utf8 this option has no effect.
74 This option does not affect mailto URIs that are passed on the command
75 line.
76--cc address
77 Specify a recipient to be copied on the e-mail.
78--bcc address
79 Specify a recipient to be blindly copied on the e-mail.
80--subject text
81 Specify a subject for the e-mail.
82--body text
83 Specify a body for the e-mail. Since the user will be able to make changes
84 before actually sending the e-mail, this can be used to provide the user
85 with a template for the e-mail. text may contain linebreaks.
86--attach file
87
88 Specify an attachment for the e-mail. file must point to an existing file.
89
90 Some e-mail applications require the file to remain present after xdg-email
91 returns.
92
93--help
94 Show command synopsis.
95--manual
96 Show this manualpage.
97--version
98 Show the xdg-utils version information.
99
100Environment Variables
101
102xdg-email honours the following environment variables:
103
104XDG_UTILS_DEBUG_LEVEL
105 Setting this environment variable to a non-zero numerical value makes
106 xdg-email do more verbose reporting on stderr. Setting a higher value
107 increases the verbosity.
108
109Exit Codes
110
111An exit code of 0 indicates success while a non-zero exit code indicates
112failure. The following failure codes can be returned:
113
1141
115 Error in command line syntax.
1162
117 One of the files passed on the command line did not exist.
1183
119 A required tool could not be found.
1204
121 The action failed.
1225
123 No permission to read one of the files passed on the command line.
124
125Configuration
126
127Visit http://portland.freedesktop.org/EmailConfig for information how to
128configure xdg-email to use the email client of your choice.
129
130Examples
131
132xdg-email 'Jeremy White <jwhite@example.com>'
133
134xdg-email --attach /tmp/logo.png \
135 --subject 'Logo contest' \
136 --body 'Attached you find the logo for the contest.' \
137 'jwhite@example.com'
138
139xdg-email --subject 'Your password is about to expire' \
140 'jwhite@example.com' 'bastian@example.com' 'whipple@example.com'
141
142_MANUALPAGE
143}
144
145usage()
146{
147cat << _USAGE
148xdg-email - command line tool for sending mail using the user's preferred
149e-mail composer
150
151Synopsis
152
153xdg-email [--utf8] [--cc address] [--bcc address] [--subject text] [--body text
154] [--attach file] [ mailto-uri | address(es) ]
155
156xdg-email { --help | --manual | --version }
157
158_USAGE
159}
160
161#@xdg-utils-common@
162
163#----------------------------------------------------------------------------
164# Common utility functions included in all XDG wrapper scripts
165#----------------------------------------------------------------------------
166
167DEBUG()
168{
169 [ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && return 0;
170 [ ${XDG_UTILS_DEBUG_LEVEL} -lt $1 ] && return 0;
171 shift
172 echo "$@" >&2
173}
174
175#-------------------------------------------------------------
176# Exit script on successfully completing the desired operation
177
178exit_success()
179{
180 if [ $# -gt 0 ]; then
181 echo "$@"
182 echo
183 fi
184
185 exit 0
186}
187
188
189#-----------------------------------------
190# Exit script on malformed arguments, not enough arguments
191# or missing required option.
192# prints usage information
193
194exit_failure_syntax()
195{
196 if [ $# -gt 0 ]; then
197 echo "xdg-email: $@" >&2
198 echo "Try 'xdg-email --help' for more information." >&2
199 else
200 usage
201 echo "Use 'man xdg-email' or 'xdg-email --manual' for additional info."
202 fi
203
204 exit 1
205}
206
207#-------------------------------------------------------------
208# Exit script on missing file specified on command line
209
210exit_failure_file_missing()
211{
212 if [ $# -gt 0 ]; then
213 echo "xdg-email: $@" >&2
214 fi
215
216 exit 2
217}
218
219#-------------------------------------------------------------
220# Exit script on failure to locate necessary tool applications
221
222exit_failure_operation_impossible()
223{
224 if [ $# -gt 0 ]; then
225 echo "xdg-email: $@" >&2
226 fi
227
228 exit 3
229}
230
231#-------------------------------------------------------------
232# Exit script on failure returned by a tool application
233
234exit_failure_operation_failed()
235{
236 if [ $# -gt 0 ]; then
237 echo "xdg-email: $@" >&2
238 fi
239
240 exit 4
241}
242
243#------------------------------------------------------------
244# Exit script on insufficient permission to read a specified file
245
246exit_failure_file_permission_read()
247{
248 if [ $# -gt 0 ]; then
249 echo "xdg-email: $@" >&2
250 fi
251
252 exit 5
253}
254
255#------------------------------------------------------------
256# Exit script on insufficient permission to read a specified file
257
258exit_failure_file_permission_write()
259{
260 if [ $# -gt 0 ]; then
261 echo "xdg-email: $@" >&2
262 fi
263
264 exit 6
265}
266
267check_input_file()
268{
269 if [ ! -e "$1" ]; then
270 exit_failure_file_missing "file '$1' does not exist"
271 fi
272 if [ ! -r "$1" ]; then
273 exit_failure_file_permission_read "no permission to read file '$1'"
274 fi
275}
276
277check_vendor_prefix()
278{
279 file_label="$2"
280 [ -n "$file_label" ] || file_label="filename"
281 file=`basename "$1"`
282 case "$file" in
283 [a-zA-Z]*-*)
284 return
285 ;;
286 esac
287
288 echo "xdg-email: $file_label '$file' does not have a proper vendor prefix" >&2
289 echo 'A vendor prefix consists of alpha characters ([a-zA-Z]) and is terminated' >&2
290 echo 'with a dash ("-"). An example '"$file_label"' is '"'example-$file'" >&2
291 echo "Use --novendor to override or 'xdg-email --manual' for additional info." >&2
292 exit 1
293}
294
295check_output_file()
296{
297 # if the file exists, check if it is writeable
298 # if it does not exists, check if we are allowed to write on the directory
299 if [ -e "$1" ]; then
300 if [ ! -w "$1" ]; then
301 exit_failure_file_permission_write "no permission to write to file '$1'"
302 fi
303 else
304 DIR=`dirname "$1"`
305 if [ ! -w "$DIR" -o ! -x "$DIR" ]; then
306 exit_failure_file_permission_write "no permission to create file '$1'"
307 fi
308 fi
309}
310
311#----------------------------------------
312# Checks for shared commands, e.g. --help
313
314check_common_commands()
315{
316 while [ $# -gt 0 ] ; do
317 parm="$1"
318 shift
319
320 case "$parm" in
321 --help)
322 usage
323 echo "Use 'man xdg-email' or 'xdg-email --manual' for additional info."
324 exit_success
325 ;;
326
327 --manual)
328 manualpage
329 exit_success
330 ;;
331
332 --version)
333 echo "xdg-email 1.0.1"
334 exit_success
335 ;;
336 esac
337 done
338}
339
340check_common_commands "$@"
341
342[ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && unset XDG_UTILS_DEBUG_LEVEL;
343if [ ${XDG_UTILS_DEBUG_LEVEL-0} -lt 1 ]; then
344 # Be silent
345 xdg_redirect_output=" > /dev/null 2> /dev/null"
346else
347 # All output to stderr
348 xdg_redirect_output=" >&2"
349fi
350
351#--------------------------------------
352# Checks for known desktop environments
353# set variable DE to the desktop environments name, lowercase
354
355detectDE()
356{
357 if [ x"$KDE_FULL_SESSION" = x"true" ]; then DE=kde;
358 elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome;
359 elif xprop -root _DT_SAVE_MODE | grep ' = \"xfce4\"$' >/dev/null 2>&1; then DE=xfce;
360 fi
361}
362
363#----------------------------------------------------------------------------
364# kfmclient exec/openURL can give bogus exit value in KDE <= 3.5.4
365# It also always returns 1 in KDE 3.4 and earlier
366# Simply return 0 in such case
367
368kfmclient_fix_exit_code()
369{
370 version=`kde${KDE_SESSION_VERSION}-config --version 2>/dev/null | grep KDE`
371 major=`echo $version | sed 's/KDE: \([0-9]\).*/\1/'`
372 minor=`echo $version | sed 's/KDE: [0-9]*\.\([0-9]\).*/\1/'`
373 release=`echo $version | sed 's/KDE: [0-9]*\.[0-9]*\.\([0-9]\).*/\1/'`
374 test "$major" -gt 3 && return $1
375 test "$minor" -gt 5 && return $1
376 test "$release" -gt 4 && return $1
377 return 0
378}
379
380open_kde()
381{
382 local client
383 if [ -f /etc/SuSE-release ] ; then
384 # Workaround for SUSE 10.0
385 client=`kreadconfig --file emaildefaults --group PROFILE_Default --key EmailClient| cut -d ' ' -f 1`
386 [ -z $client ] && client="kmail"
387 if ! which $client > /dev/null 2> /dev/null; then
388 DEBUG 3 "KDE has $client configured as email client which isn't installed"
389 if which gnome-open > /dev/null 2> /dev/null && which evolution > /dev/null 2> /dev/null; then
390 DEBUG 3 "Try gnome-open instead"
391 open_gnome "$1"
392 fi
393 fi
394 fi
395 DEBUG 1 "Running kmailservice \"$1\""
396 # KDE uses locale's encoding when decoding the URI, so set it to UTF-8
397 LC_ALL=C.UTF-8 kmailservice "$1"
398 kfmclient_fix_exit_code $?
399
400 if [ $? -eq 0 ]; then
401 exit_success
402 else
403 exit_failure_operation_failed
404 fi
405}
406
407open_gnome()
408{
409 DEBUG 1 "Running gnome-open \"$1\""
410 gnome-open "$1"
411
412 if [ $? -eq 0 ]; then
413 exit_success
414 else
415 exit_failure_operation_failed
416 fi
417}
418
419
420open_xfce()
421{
422 DEBUG 1 "Running exo-open \"$1\""
423 exo-open "$1"
424
425 if [ $? -eq 0 ]; then
426 exit_success
427 else
428 exit_failure_operation_failed
429 fi
430}
431
432open_generic()
433{
434 IFS=":"
435 for browser in $BROWSER; do
436 if [ x"$browser" != x"" ]; then
437
438 IFS=' '
439 browser_with_arg=${browser//'%s'/"$1"}
440
441 if [ x"$browser_with_arg" = x"$browser" ]; then "$browser" "$1";
442 else $browser_with_arg;
443 fi
444
445 if [ $? -eq 0 ]; then exit_success;
446 fi
447 fi
448 done
449
450 exit_failure_operation_impossible "no method available for opening '$1'"
451}
452
453url_encode()
454{
455result=$(echo "$1" | $utf8 | awk '
456 BEGIN {
457 for ( i=1; i<=255; ++i ) ord [ sprintf ("%c", i) "" ] = i + 0
458 e = ""
459 linenr = 1
460 }
461 {
462 if ( linenr++ != 1 ) {
463 e = e "%0D%0A"
464 }
465 for ( i=1; i<=length ($0); ++i ) {
466 c = substr ($0, i, 1)
467 if ( ord [c] > 127 ) {
468 e = e "%" sprintf("%02X", ord [c])
469 } else if ( c ~ /[@a-zA-Z0-9.-]/ ) {
470 e = e c
471 } else {
472 e = e "%" sprintf("%02X", ord [c])
473 }
474 }
475 }
476 END {
477 print e
478 }
479')
480}
481
482options=
483mailto=
484utf8="iconv -t utf8"
485while [ $# -gt 0 ] ; do
486 parm="$1"
487 shift
488
489 case "$parm" in
490 --utf8)
491 utf8="cat"
492 ;;
493
494 --to)
495 if [ -z "$1" ] ; then
496 exit_failure_syntax "email address argument missing for --to"
497 fi
498 url_encode "$1"
499 options="${options}to=${result}&"
500 shift
501 ;;
502
503 --cc)
504 if [ -z "$1" ] ; then
505 exit_failure_syntax "email address argument missing for --cc"
506 fi
507 url_encode "$1"
508 options="${options}cc=${result}&"
509 shift
510 ;;
511
512 --bcc)
513 if [ -z "$1" ] ; then
514 exit_failure_syntax "email address argument missing for --bcc"
515 fi
516 url_encode "$1"
517 options="${options}bcc=${result}&"
518 shift
519 ;;
520
521 --subject)
522 if [ -z "$1" ] ; then
523 exit_failure_syntax "text argument missing for --subject option"
524 fi
525 url_encode "$1"
526 options="${options}subject=${result}&"
527 shift
528 ;;
529
530 --body)
531 if [ -z "$1" ] ; then
532 exit_failure_syntax "text argument missing for --body option"
533 fi
534 url_encode "$1"
535 options="${options}body=${result}&"
536 shift
537 ;;
538
539 --attach)
540 if [ -z "$1" ] ; then
541 exit_failure_syntax "file argument missing for --attach option"
542 fi
543 check_input_file "$1"
544 file=`readlink -f "$1"` # Normalize path
545 if [ -z "$file" -o ! -f "$file" ] ; then
546 exit_failure_file_missing "file '$1' does not exist"
547 fi
548
549 url_encode "$file"
550 options="${options}attach=${result}&"
551 shift
552 ;;
553
554 -*)
555 exit_failure_syntax "unexpected option '$parm'"
556 ;;
557
558 mailto:*)
559 mailto="$parm"
560 ;;
561
562 *@*)
563 url_encode "$parm"
564 if [ -z "${mailto}" ] ; then
565 mailto="mailto:"${result}"?"
566 else
567 options="${options}to=${result}&"
568 fi
569 ;;
570
571 *)
572 exit_failure_syntax "unexpected argument '$parm'"
573 ;;
574 esac
575done
576
577if [ -z "${mailto}" ] ; then
578 # TO address is optional
579 mailto="mailto:?"
580fi
581
582case $mailto in
583 *\?)
584 mailto="${mailto}${options}"
585 ;;
586
587 *\?*)
588 mailto="${mailto}&${options}"
589 ;;
590
591 *)
592 mailto="${mailto}?${options}"
593 ;;
594esac
595
596# Strip trailing ? and &
597mailto=`echo "${mailto}"| sed 's/[?&]$//'`
598
599# Shouldn't happen
600[ x"${mailto}" != x"" ] || exit_failure_syntax
601
602if which xdg-email-hook.sh > /dev/null 2> /dev/null; then
603 xdg-email-hook.sh "${mailto}"
604 if [ $? -eq 0 ]; then
605 exit_success
606 else
607 exit_failure_operation_failed
608 fi
609fi
610
611detectDE
612
613if [ x"$DE" = x"" ]; then
614 # if BROWSER variable is not set, check some well known browsers instead
615 if [ x"$BROWSER" = x"" ]; then
616 BROWSER=firefox:mozilla:netscape
617 fi
618 DE=generic
619fi
620
621case "$DE" in
622 kde)
623 open_kde "${mailto}"
624 ;;
625
626 gnome)
627 open_gnome "${mailto}"
628 ;;
629
630 xfce)
631 open_xfce "${mailto}"
632 ;;
633
634 generic)
635 open_generic "${mailto}"
636 ;;
637
638 *)
639 exit_failure_operation_impossible "no method available for opening '${mailto}'"
640 ;;
641esac