blob: ea9f8bab30cbe5523c536510c16d34f97938edc6 [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\""
mdm@chromium.orgad856b92009-07-27 21:50:25 +0000396 if [ x"$KDE_SESSION_VERSION" = x"4" ]; then
397 KMAILSERVICE=`kde4-config --locate kmailservice --path exe 2>/dev/null`
398 else
399 KMAILSERVICE=`which kmailservice 2>/dev/null`
400 fi
dkegel@google.comf20da1f2009-06-30 19:16:32 +0000401 # KDE uses locale's encoding when decoding the URI, so set it to UTF-8
mdm@chromium.orgad856b92009-07-27 21:50:25 +0000402 LC_ALL=C.UTF-8 $KMAILSERVICE "$1"
dkegel@google.comf20da1f2009-06-30 19:16:32 +0000403 kfmclient_fix_exit_code $?
404
405 if [ $? -eq 0 ]; then
406 exit_success
407 else
408 exit_failure_operation_failed
409 fi
410}
411
412open_gnome()
413{
414 DEBUG 1 "Running gnome-open \"$1\""
415 gnome-open "$1"
416
417 if [ $? -eq 0 ]; then
418 exit_success
419 else
420 exit_failure_operation_failed
421 fi
422}
423
424
425open_xfce()
426{
427 DEBUG 1 "Running exo-open \"$1\""
428 exo-open "$1"
429
430 if [ $? -eq 0 ]; then
431 exit_success
432 else
433 exit_failure_operation_failed
434 fi
435}
436
437open_generic()
438{
439 IFS=":"
440 for browser in $BROWSER; do
441 if [ x"$browser" != x"" ]; then
442
443 IFS=' '
444 browser_with_arg=${browser//'%s'/"$1"}
445
446 if [ x"$browser_with_arg" = x"$browser" ]; then "$browser" "$1";
447 else $browser_with_arg;
448 fi
449
450 if [ $? -eq 0 ]; then exit_success;
451 fi
452 fi
453 done
454
455 exit_failure_operation_impossible "no method available for opening '$1'"
456}
457
458url_encode()
459{
460result=$(echo "$1" | $utf8 | awk '
461 BEGIN {
462 for ( i=1; i<=255; ++i ) ord [ sprintf ("%c", i) "" ] = i + 0
463 e = ""
464 linenr = 1
465 }
466 {
467 if ( linenr++ != 1 ) {
468 e = e "%0D%0A"
469 }
470 for ( i=1; i<=length ($0); ++i ) {
471 c = substr ($0, i, 1)
472 if ( ord [c] > 127 ) {
473 e = e "%" sprintf("%02X", ord [c])
474 } else if ( c ~ /[@a-zA-Z0-9.-]/ ) {
475 e = e c
476 } else {
477 e = e "%" sprintf("%02X", ord [c])
478 }
479 }
480 }
481 END {
482 print e
483 }
484')
485}
486
487options=
488mailto=
489utf8="iconv -t utf8"
490while [ $# -gt 0 ] ; do
491 parm="$1"
492 shift
493
494 case "$parm" in
495 --utf8)
496 utf8="cat"
497 ;;
498
499 --to)
500 if [ -z "$1" ] ; then
501 exit_failure_syntax "email address argument missing for --to"
502 fi
503 url_encode "$1"
504 options="${options}to=${result}&"
505 shift
506 ;;
507
508 --cc)
509 if [ -z "$1" ] ; then
510 exit_failure_syntax "email address argument missing for --cc"
511 fi
512 url_encode "$1"
513 options="${options}cc=${result}&"
514 shift
515 ;;
516
517 --bcc)
518 if [ -z "$1" ] ; then
519 exit_failure_syntax "email address argument missing for --bcc"
520 fi
521 url_encode "$1"
522 options="${options}bcc=${result}&"
523 shift
524 ;;
525
526 --subject)
527 if [ -z "$1" ] ; then
528 exit_failure_syntax "text argument missing for --subject option"
529 fi
530 url_encode "$1"
531 options="${options}subject=${result}&"
532 shift
533 ;;
534
535 --body)
536 if [ -z "$1" ] ; then
537 exit_failure_syntax "text argument missing for --body option"
538 fi
539 url_encode "$1"
540 options="${options}body=${result}&"
541 shift
542 ;;
543
544 --attach)
545 if [ -z "$1" ] ; then
546 exit_failure_syntax "file argument missing for --attach option"
547 fi
548 check_input_file "$1"
549 file=`readlink -f "$1"` # Normalize path
550 if [ -z "$file" -o ! -f "$file" ] ; then
551 exit_failure_file_missing "file '$1' does not exist"
552 fi
553
554 url_encode "$file"
555 options="${options}attach=${result}&"
556 shift
557 ;;
558
559 -*)
560 exit_failure_syntax "unexpected option '$parm'"
561 ;;
562
563 mailto:*)
564 mailto="$parm"
565 ;;
566
567 *@*)
568 url_encode "$parm"
569 if [ -z "${mailto}" ] ; then
570 mailto="mailto:"${result}"?"
571 else
572 options="${options}to=${result}&"
573 fi
574 ;;
575
576 *)
577 exit_failure_syntax "unexpected argument '$parm'"
578 ;;
579 esac
580done
581
582if [ -z "${mailto}" ] ; then
583 # TO address is optional
584 mailto="mailto:?"
585fi
586
587case $mailto in
588 *\?)
589 mailto="${mailto}${options}"
590 ;;
591
592 *\?*)
593 mailto="${mailto}&${options}"
594 ;;
595
596 *)
597 mailto="${mailto}?${options}"
598 ;;
599esac
600
601# Strip trailing ? and &
602mailto=`echo "${mailto}"| sed 's/[?&]$//'`
603
604# Shouldn't happen
605[ x"${mailto}" != x"" ] || exit_failure_syntax
606
607if which xdg-email-hook.sh > /dev/null 2> /dev/null; then
608 xdg-email-hook.sh "${mailto}"
609 if [ $? -eq 0 ]; then
610 exit_success
611 else
612 exit_failure_operation_failed
613 fi
614fi
615
616detectDE
617
618if [ x"$DE" = x"" ]; then
619 # if BROWSER variable is not set, check some well known browsers instead
620 if [ x"$BROWSER" = x"" ]; then
621 BROWSER=firefox:mozilla:netscape
622 fi
623 DE=generic
624fi
625
626case "$DE" in
627 kde)
628 open_kde "${mailto}"
629 ;;
630
631 gnome)
632 open_gnome "${mailto}"
633 ;;
634
635 xfce)
636 open_xfce "${mailto}"
637 ;;
638
639 generic)
640 open_generic "${mailto}"
641 ;;
642
643 *)
644 exit_failure_operation_impossible "no method available for opening '${mailto}'"
645 ;;
646esac