mhc 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/COPYRIGHT +28 -0
  6. data/Gemfile +8 -0
  7. data/README.org +209 -0
  8. data/Rakefile +13 -0
  9. data/bin/mhc +312 -0
  10. data/emacs/Cask +25 -0
  11. data/emacs/Makefile +58 -0
  12. data/emacs/mhc-calendar.el +1723 -0
  13. data/emacs/mhc-calfw.el +135 -0
  14. data/emacs/mhc-compat.el +90 -0
  15. data/emacs/mhc-date.el +642 -0
  16. data/emacs/mhc-day.el +149 -0
  17. data/emacs/mhc-db.el +158 -0
  18. data/emacs/mhc-draft.el +211 -0
  19. data/emacs/mhc-e21.el +167 -0
  20. data/emacs/mhc-face.el +236 -0
  21. data/emacs/mhc-file.el +224 -0
  22. data/emacs/mhc-guess.el +648 -0
  23. data/emacs/mhc-header.el +176 -0
  24. data/emacs/mhc-logic.el +563 -0
  25. data/emacs/mhc-message.el +130 -0
  26. data/emacs/mhc-minibuf.el +466 -0
  27. data/emacs/mhc-misc.el +248 -0
  28. data/emacs/mhc-mua.el +260 -0
  29. data/emacs/mhc-parse.el +286 -0
  30. data/emacs/mhc-process.el +35 -0
  31. data/emacs/mhc-ps.el +1174 -0
  32. data/emacs/mhc-record.el +201 -0
  33. data/emacs/mhc-schedule.el +202 -0
  34. data/emacs/mhc-summary.el +763 -0
  35. data/emacs/mhc-sync.el +158 -0
  36. data/emacs/mhc-vars.el +149 -0
  37. data/emacs/mhc.el +1114 -0
  38. data/icons/Anniversary.xbm +6 -0
  39. data/icons/Anniversary.xpm +27 -0
  40. data/icons/Birthday.xbm +6 -0
  41. data/icons/Birthday.xpm +25 -0
  42. data/icons/Business.xbm +6 -0
  43. data/icons/Business.xpm +24 -0
  44. data/icons/CheckBox.xbm +6 -0
  45. data/icons/CheckBox.xpm +24 -0
  46. data/icons/CheckedBox.xbm +6 -0
  47. data/icons/CheckedBox.xpm +25 -0
  48. data/icons/Conflict.xbm +6 -0
  49. data/icons/Conflict.xpm +22 -0
  50. data/icons/Date.xbm +6 -0
  51. data/icons/Date.xpm +29 -0
  52. data/icons/Holiday.xbm +6 -0
  53. data/icons/Holiday.xpm +25 -0
  54. data/icons/Link.xbm +6 -0
  55. data/icons/Link.xpm +25 -0
  56. data/icons/Other.xbm +6 -0
  57. data/icons/Other.xpm +28 -0
  58. data/icons/Party.xbm +6 -0
  59. data/icons/Party.xpm +23 -0
  60. data/icons/Private.xbm +6 -0
  61. data/icons/Private.xpm +26 -0
  62. data/icons/Recurrence.xbm +6 -0
  63. data/icons/Recurrence.xpm +98 -0
  64. data/icons/Vacation.xbm +6 -0
  65. data/icons/Vacation.xpm +26 -0
  66. data/lib/mhc.rb +45 -0
  67. data/lib/mhc/builder.rb +64 -0
  68. data/lib/mhc/caldav.rb +304 -0
  69. data/lib/mhc/calendar.rb +106 -0
  70. data/lib/mhc/command.rb +13 -0
  71. data/lib/mhc/command/cache.rb +14 -0
  72. data/lib/mhc/command/completions.rb +108 -0
  73. data/lib/mhc/command/init.rb +133 -0
  74. data/lib/mhc/command/scan.rb +33 -0
  75. data/lib/mhc/command/sync.rb +22 -0
  76. data/lib/mhc/config.rb +229 -0
  77. data/lib/mhc/converter.rb +330 -0
  78. data/lib/mhc/datastore.rb +164 -0
  79. data/lib/mhc/date_enumerator.rb +274 -0
  80. data/lib/mhc/date_frame.rb +124 -0
  81. data/lib/mhc/date_helper.rb +49 -0
  82. data/lib/mhc/etag.rb +68 -0
  83. data/lib/mhc/event.rb +396 -0
  84. data/lib/mhc/formatter.rb +312 -0
  85. data/lib/mhc/logger.rb +94 -0
  86. data/lib/mhc/modifier.rb +149 -0
  87. data/lib/mhc/occurrence.rb +94 -0
  88. data/lib/mhc/occurrence_enumerator.rb +113 -0
  89. data/lib/mhc/property_value.rb +33 -0
  90. data/lib/mhc/property_value/date.rb +190 -0
  91. data/lib/mhc/property_value/integer.rb +15 -0
  92. data/lib/mhc/property_value/list.rb +41 -0
  93. data/lib/mhc/property_value/period.rb +49 -0
  94. data/lib/mhc/property_value/range.rb +100 -0
  95. data/lib/mhc/property_value/recurrence_condition.rb +272 -0
  96. data/lib/mhc/property_value/text.rb +11 -0
  97. data/lib/mhc/property_value/time.rb +45 -0
  98. data/lib/mhc/query.rb +210 -0
  99. data/lib/mhc/sync.rb +46 -0
  100. data/lib/mhc/sync/driver.rb +108 -0
  101. data/lib/mhc/sync/status.rb +70 -0
  102. data/lib/mhc/sync/status_manager.rb +142 -0
  103. data/lib/mhc/sync/strategy.rb +233 -0
  104. data/lib/mhc/sync/syncinfo.rb +98 -0
  105. data/lib/mhc/templates/config.yml.erb +142 -0
  106. data/lib/mhc/version.rb +4 -0
  107. data/lib/mhc/webdav.rb +319 -0
  108. data/mhc.gemspec +24 -0
  109. data/samples/DOT.mhc-config.yml +116 -0
  110. data/samples/japanese-holidays.mhcc +153 -0
  111. data/samples/mhc-completions.zsh +11 -0
  112. data/spec/mhc_spec.rb +682 -0
  113. data/spec/spec_helper.rb +9 -0
  114. data/xpm/close.xpm +18 -0
  115. data/xpm/delete.xpm +19 -0
  116. data/xpm/exit.xpm +18 -0
  117. data/xpm/month.xpm +18 -0
  118. data/xpm/next.xpm +18 -0
  119. data/xpm/next2.xpm +18 -0
  120. data/xpm/next_year.xpm +18 -0
  121. data/xpm/open.xpm +19 -0
  122. data/xpm/prev.xpm +18 -0
  123. data/xpm/prev2.xpm +18 -0
  124. data/xpm/prev_year.xpm +18 -0
  125. data/xpm/save.xpm +19 -0
  126. data/xpm/today.xpm +18 -0
  127. metadata +214 -0
data/emacs/mhc-sync.el ADDED
@@ -0,0 +1,158 @@
1
+ ;;; -*- emacs-lisp -*-
2
+ ;; mhc-sync.el -- mhc-sync (ruby script) interface
3
+ ;;
4
+ ;; Author: Hideyuki SHIRAI <shirai@quickhack.net>
5
+ ;;
6
+ ;; Created: 2000/06/12
7
+ ;; Revised: $Date: 2002/11/11 05:27:15 $
8
+
9
+ ;;; Commentary:
10
+
11
+ ;; This file is a part of MHC, includes backend functions to
12
+ ;; manipulate schedule files.
13
+
14
+
15
+ ;;; Customize Variables:
16
+ (defcustom mhc-sync-id nil
17
+ "*Identical id of mhc-sync (-x option)."
18
+ :group 'mhc
19
+ :type 'string)
20
+
21
+ (defcustom mhc-sync-remote nil
22
+ "*Remote server repository of mhc-sync ([user@]remote.host[:dir])."
23
+ :group 'mhc
24
+ :type 'string)
25
+
26
+ (defcustom mhc-sync-localdir nil
27
+ "*Local repository directory of mhc-sync (-r option)."
28
+ :group 'mhc
29
+ :type 'string)
30
+
31
+ (defcustom mhc-sync-coding-system
32
+ (if (>= emacs-major-version 20) 'undecided '*autoconv*)
33
+ "*Default coding system for process of mhc-sync."
34
+ :group 'mhc
35
+ :type 'symbol)
36
+
37
+
38
+ ;;; Interanal variabiles:
39
+ (defconst mhc-sync/passwd-regexp "password:\\|passphrase:\\|Enter passphrase")
40
+
41
+ (defvar mhc-sync/process nil)
42
+
43
+ (defvar mhc-sync/req-passwd nil)
44
+
45
+
46
+ ;;; Code:
47
+ (defun mhc-sync/backup-and-remove (file &optional offline)
48
+ "Backend function to remove FILE."
49
+ (let ((file (expand-file-name file))
50
+ (new-path (expand-file-name
51
+ "trash"
52
+ (mhc-config-base-directory))))
53
+ (or (file-directory-p new-path)
54
+ (make-directory new-path))
55
+ (rename-file file (mhc-misc-get-new-path new-path file))))
56
+
57
+ (defun mhc-sync/start-process (&optional full)
58
+ (cond
59
+ ((not (and (stringp mhc-sync-remote) (stringp mhc-sync-id)))
60
+ (message "No remote server specified.")
61
+ nil)
62
+ ((processp mhc-sync/process)
63
+ (message "another mhc-sync running.")
64
+ nil)
65
+ (t
66
+ (let ((buf (mhc-get-buffer-create " *mhc-sync*"))
67
+ (ldir (expand-file-name (or mhc-sync-localdir "~/Mail/schedule"))))
68
+ (mhc-window-push)
69
+ (pop-to-buffer buf)
70
+ (setq buffer-read-only nil)
71
+ (erase-buffer)
72
+ (setq buffer-read-only t)
73
+ (message "mhc-sync...")
74
+ (setq mhc-sync/req-passwd t)
75
+ (setq mhc-sync/process
76
+ (apply (function start-process)
77
+ "mhc-sync" buf "mhc-sync"
78
+ (list "-x" mhc-sync-id "-r" ldir mhc-sync-remote)))
79
+ (set-process-coding-system mhc-sync/process mhc-sync-coding-system)
80
+ (set-process-filter mhc-sync/process 'mhc-sync/filter)
81
+ (set-process-sentinel mhc-sync/process 'mhc-sync/sentinel)
82
+ (if (featurep 'xemacs)
83
+ (while mhc-sync/process
84
+ (accept-process-output))
85
+ (while mhc-sync/process
86
+ (sit-for 0.1)
87
+ (discard-input)))
88
+ (sit-for 1)
89
+ (mhc-window-pop)
90
+ (or (and (mhc-summary-buffer-p)
91
+ (mhc-rescan-month mhc-default-hide-private-schedules))
92
+ (and (mhc-calendar-p) (mhc-calendar-rescan)))
93
+ t))))
94
+
95
+ (defun mhc-sync/filter (process string)
96
+ (if (bufferp (process-buffer process))
97
+ (let ((obuf (buffer-name)))
98
+ (unwind-protect
99
+ (progn
100
+ (set-buffer (process-buffer process))
101
+ (let ((buffer-read-only nil)
102
+ passwd)
103
+ (goto-char (point-max))
104
+ (insert string)
105
+ (cond
106
+ ((and mhc-sync/req-passwd
107
+ (string-match mhc-sync/passwd-regexp string))
108
+ (setq passwd (mhc-misc-read-passwd string))
109
+ (process-send-string process (concat passwd "\n")))
110
+ ((string-match "---------------------" string)
111
+ (setq mhc-sync/req-passwd nil)))))
112
+ (if (get-buffer obuf)
113
+ (set-buffer obuf))))))
114
+
115
+ (defun mhc-sync/sentinel (process event)
116
+ (when (bufferp (process-buffer process))
117
+ (pop-to-buffer (process-buffer process))
118
+ (let ((buffer-read-only nil))
119
+ (goto-char (point-max))
120
+ (insert "<<<transfer finish>>>")))
121
+ (setq mhc-sync/process nil))
122
+
123
+
124
+ (provide 'mhc-sync)
125
+ (put 'mhc-sync 'remove 'mhc-sync/backup-and-remove)
126
+ (put 'mhc-sync 'sync 'mhc-sync/start-process)
127
+
128
+ ;;; Copyright Notice:
129
+
130
+ ;; Copyright (C) 2000 MHC developing team. All rights reserved.
131
+
132
+ ;; Redistribution and use in source and binary forms, with or without
133
+ ;; modification, are permitted provided that the following conditions
134
+ ;; are met:
135
+ ;;
136
+ ;; 1. Redistributions of source code must retain the above copyright
137
+ ;; notice, this list of conditions and the following disclaimer.
138
+ ;; 2. Redistributions in binary form must reproduce the above copyright
139
+ ;; notice, this list of conditions and the following disclaimer in the
140
+ ;; documentation and/or other materials provided with the distribution.
141
+ ;; 3. Neither the name of the team nor the names of its contributors
142
+ ;; may be used to endorse or promote products derived from this software
143
+ ;; without specific prior written permission.
144
+ ;;
145
+ ;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS''
146
+ ;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
147
+ ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
148
+ ;; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
149
+ ;; THE TEAM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
150
+ ;; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
151
+ ;; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
152
+ ;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
153
+ ;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
154
+ ;; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
155
+ ;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
156
+ ;; OF THE POSSIBILITY OF SUCH DAMAGE.
157
+
158
+ ;; mhc-sync.el ends here
data/emacs/mhc-vars.el ADDED
@@ -0,0 +1,149 @@
1
+ ;;; -*- mode: Emacs-Lisp; coding: utf-8 -*-
2
+
3
+ ;; Author: Yoshinari Nomura <nom@quickhack.net>,
4
+ ;; Created: 2000/04/30
5
+ ;; Revised: $Date$
6
+
7
+
8
+ ;;; Commentary:
9
+
10
+ ;; This file is a part of MHC, and includes defintions of global
11
+ ;; confiration variables.
12
+
13
+
14
+ ;;; Code:
15
+ (require 'mhc-compat)
16
+ (require 'mhc-process)
17
+
18
+
19
+ ;;; Constants:
20
+ (defconst mhc-version "mhc 1.0.0")
21
+
22
+
23
+ ;;; Configration Variables:
24
+ (defgroup mhc nil
25
+ "Various sorts of MH Calender."
26
+ :group 'mail)
27
+
28
+ (defcustom mhc-mailer-package 'mua
29
+ "*Variable to set your favorite mailer."
30
+ :group 'mhc
31
+ :type '(radio (const :tag "Mew" mew)
32
+ (const :tag "Wanderlust" wl)
33
+ (const :tag "Gnus" gnus)))
34
+
35
+ (defcustom mhc-start-day-of-week 0
36
+ "*Day of the week as the start of the week."
37
+ :group 'mhc
38
+ :type '(choice (const :tag "Sunday" 0)
39
+ (const :tag "Monday" 1)
40
+ (const :tag "Tuesday" 2)
41
+ (const :tag "Wednesday" 3)
42
+ (const :tag "Thursday" 4)
43
+ (const :tag "Friday" 5)
44
+ (const :tag "Saturday" 6)))
45
+
46
+ (defcustom mhc-insert-calendar t
47
+ "*If non nil value, display vertical calender."
48
+ :group 'mhc
49
+ :type 'boolean)
50
+
51
+ (defcustom mhc-vertical-calendar-length 3
52
+ "*Length of vertical calendar in summary buffer."
53
+ :group 'mhc
54
+ :type '(radio (integer :tag "Show length (current month is center)" 3)
55
+ (cons (integer :tag " Show length" 3)
56
+ (integer :tag "Length of before current" 1))))
57
+
58
+ (defcustom mhc-default-coding-system
59
+ (if (>= emacs-major-version 20) 'utf-8-unix '*iso-2022-ss2-7*)
60
+ "*Default coding system for MHC schedule files."
61
+ :group 'mhc
62
+ :type 'symbol)
63
+
64
+ (defcustom mhc-default-hide-private-schedules nil
65
+ "*If non-nil value, hide private schedules."
66
+ :group 'mhc
67
+ :type 'boolean)
68
+
69
+ (defcustom mhc-category-as-private '("private")
70
+ "*String list of private categories."
71
+ :group 'mhc
72
+ :type '(repeat (string :tag "Category")))
73
+
74
+ (defcustom mhc-default-network-status t
75
+ "*Flag of the default network status."
76
+ :group 'mhc
77
+ :type 'boolean)
78
+
79
+ (defcustom mhc-show-network-status t
80
+ "*Flag to show the network status."
81
+ :group 'mhc
82
+ :type 'boolean)
83
+
84
+ (defcustom mhc-use-cache t
85
+ "*Flag to decide whether to use cache or not."
86
+ :group 'mhc
87
+ :type '(radio (const :tag "Use" t)
88
+ (const :tag "Lazy check" 0)
89
+ (const :tag "No use" nil)))
90
+
91
+ (defcustom mhc-use-wide-scope nil
92
+ "*Wide scope method in summary mode."
93
+ :group 'mhc
94
+ :type '(radio (const :tag "No use" nil)
95
+ (const :tag "Complete week scope" week)
96
+ (const :tag "Wide week scope" wide)
97
+ (integer :tag "Scope wide size (>=0)" 3)))
98
+
99
+ (defcustom mhc-default-alarm "5 minute"
100
+ "*Default alarm string in making draft."
101
+ :group 'mhc
102
+ :type 'string)
103
+
104
+ (defcustom mhc-ask-alarm nil
105
+ "*If non-nil value, ask the alarm string in making draft."
106
+ :group 'mhc
107
+ :type 'boolean)
108
+
109
+ (defun mhc-config-get-property (&optional dot-separated-key)
110
+ (mhc-process-send-command
111
+ (format "config --format=emacs %s" (or dot-separated-key ""))))
112
+
113
+ (defun mhc-config-base-directory ()
114
+ (expand-file-name (mhc-config-get-property "general.repository")))
115
+
116
+ (provide 'mhc-vars)
117
+
118
+ ;;; Copyright Notice:
119
+
120
+ ;; Copyright (C) 1999, 2000 Yoshinari Nomura. All rights reserved.
121
+ ;; Copyright (C) 2000 MHC developing team. All rights reserved.
122
+
123
+ ;; Redistribution and use in source and binary forms, with or without
124
+ ;; modification, are permitted provided that the following conditions
125
+ ;; are met:
126
+ ;;
127
+ ;; 1. Redistributions of source code must retain the above copyright
128
+ ;; notice, this list of conditions and the following disclaimer.
129
+ ;; 2. Redistributions in binary form must reproduce the above copyright
130
+ ;; notice, this list of conditions and the following disclaimer in the
131
+ ;; documentation and/or other materials provided with the distribution.
132
+ ;; 3. Neither the name of the team nor the names of its contributors
133
+ ;; may be used to endorse or promote products derived from this software
134
+ ;; without specific prior written permission.
135
+ ;;
136
+ ;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS''
137
+ ;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
138
+ ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
139
+ ;; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
140
+ ;; THE TEAM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
141
+ ;; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
142
+ ;; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
143
+ ;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
144
+ ;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
145
+ ;; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
146
+ ;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
147
+ ;; OF THE POSSIBILITY OF SUCH DAMAGE.
148
+
149
+ ;;; mhc-vars.el ends here
data/emacs/mhc.el ADDED
@@ -0,0 +1,1114 @@
1
+ ;;; mhc.el --- MH Calendar.
2
+
3
+ ;; Author: Yoshinari Nomura <nom@quickhack.net>
4
+ ;;
5
+ ;; Created: 1994/07/04
6
+ ;; Revised: $Date: 2009/05/31 12:54:50 $
7
+
8
+ ;;;
9
+ ;;; Commentary:
10
+ ;;;
11
+
12
+ ;; Mhc is the personal schedule management package cooperating
13
+ ;; with Mew, Wanderlust or Gnus.
14
+ ;;
15
+ ;; Minimum setup:
16
+ ;;
17
+ ;; for Mew user:
18
+ ;; (autoload 'mhc-mew-setup "mhc-mew")
19
+ ;; (add-hook 'mew-init-hook 'mhc-mew-setup)
20
+ ;;
21
+ ;; for Wanderlust user:
22
+ ;; (autoload 'mhc-wl-setup "mhc-wl")
23
+ ;; (add-hook 'wl-init-hook 'mhc-wl-setup)
24
+ ;;
25
+ ;; for Gnus user:
26
+ ;; (autoload 'mhc-gnus-setup "mhc-gnus")
27
+ ;; (add-hook 'gnus-startup-hook 'mhc-gnus-setup)
28
+
29
+ ;;; Code:
30
+
31
+ (eval-when-compile (require 'cl))
32
+
33
+ ;; For Mule 2.3
34
+ (eval-and-compile
35
+ (when (boundp 'MULE)
36
+ (require 'poe)
37
+ (require 'pcustom)))
38
+
39
+ (require 'mhc-vars)
40
+ (require 'mhc-record)
41
+ (require 'mhc-parse)
42
+ (require 'mhc-file)
43
+ (require 'mhc-process)
44
+ (require 'mhc-db)
45
+ (require 'mhc-message)
46
+ (require 'mhc-misc)
47
+ (require 'mhc-date)
48
+ (require 'mhc-guess)
49
+ (require 'mhc-schedule)
50
+ (require 'mhc-face)
51
+ (require 'mhc-calendar)
52
+ (require 'mhc-draft)
53
+
54
+ (cond
55
+ ((eval-when-compile (and (not (featurep 'xemacs))
56
+ (>= emacs-major-version 21)
57
+ (if (eq system-type 'windows-nt)
58
+ ;; Meadow2 or NTEmacs21.3(and the later
59
+ ;; version) supports the image feature.
60
+ (or (featurep 'meadow)
61
+ (>= emacs-major-version 22)
62
+ (>= emacs-minor-version 3))
63
+ t)))
64
+ (require 'mhc-e21))
65
+ ((eval-when-compile
66
+ (condition-case nil
67
+ (require 'bitmap)
68
+ (error nil)))
69
+ (require 'mhc-bm))
70
+ ((eval-when-compile (featurep 'xemacs))
71
+ (require 'mhc-xmas))
72
+ (t (defun mhc-use-icon-p ())))
73
+
74
+ (require 'mhc-minibuf)
75
+ (require 'mhc-summary)
76
+ (provide 'mhc)
77
+
78
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
79
+ ;; Menu setup
80
+ ;;
81
+ (defvar mhc-mode-menu-spec
82
+ '("Mhc"
83
+ ["This month" mhc-goto-this-month t]
84
+ ["Next month" mhc-goto-next-month t]
85
+ ["Prev month" mhc-goto-prev-month t]
86
+ ["Goto month" mhc-goto-month t]
87
+ ["Goto date" mhc-goto-date t]
88
+ ["Import" mhc-import t]
89
+ ["Set category" mhc-set-default-category t]
90
+ "----"
91
+ ["Goto today" mhc-goto-today (mhc-summary-buffer-p)]
92
+ ["Modify" mhc-modify (mhc-summary-buffer-p)]
93
+ ["Edit" mhc-edit (mhc-summary-buffer-p)]
94
+ ["Rescan" mhc-rescan-month (mhc-summary-buffer-p)]
95
+ ["Delete" mhc-delete (mhc-summary-buffer-p)]
96
+ ["Insert Schedule" mhc-insert-schedule (not buffer-read-only)]
97
+ ["3 months Mini calendar" mhc-calendar t]
98
+ ["Toggle 3 months calendar" mhc-calendar-toggle-insert-rectangle
99
+ (mhc-summary-buffer-p)]
100
+ "----"
101
+ ["Reset" mhc-reset (mhc-summary-buffer-p)]
102
+ ("Network"
103
+ ["Online" mhc-file-toggle-offline mhc-file/offline]
104
+ ["Offline" mhc-file-toggle-offline (not mhc-file/offline)]
105
+ ["Sync" mhc-file-sync (and (not (and mhc-file/offline
106
+ (not mhc-file-sync-enable-offline)))
107
+ (if (eq mhc-file-method 'mhc-sync)
108
+ (and (stringp mhc-sync-remote)
109
+ (stringp mhc-sync-id))
110
+ mhc-file-method))])
111
+ "----"
112
+ ("PostScript"
113
+ ["PostScript" mhc-ps t]
114
+ ["Preview" mhc-ps-preview t]
115
+ ["Print" mhc-ps-print t]
116
+ ["Save" mhc-ps-save t]
117
+ ["Insert buffer" mhc-ps-insert-buffer t])))
118
+
119
+ (defvar mhc-prefix-key "\C-c."
120
+ "*Prefix key to call MHC functions.")
121
+
122
+ (defvar mhc-mode-map nil "Keymap for `mhc-mode'.")
123
+ (defvar mhc-prefix-map nil "Keymap for 'mhc-key-prefix'.")
124
+
125
+ (if (and mhc-mode-map mhc-prefix-map)
126
+ ()
127
+ (setq mhc-mode-map (make-sparse-keymap))
128
+ (setq mhc-prefix-map (make-sparse-keymap))
129
+ (define-key mhc-prefix-map "g" 'mhc-goto-month)
130
+ (define-key mhc-prefix-map "j" 'mhc-goto-date)
131
+ (define-key mhc-prefix-map "." 'mhc-goto-this-month)
132
+ (define-key mhc-prefix-map "n" 'mhc-goto-next-month)
133
+ (define-key mhc-prefix-map "N" 'mhc-goto-next-year)
134
+ (define-key mhc-prefix-map "p" 'mhc-goto-prev-month)
135
+ (define-key mhc-prefix-map "P" 'mhc-goto-prev-year)
136
+ (define-key mhc-prefix-map "f" 'mhc-goto-today)
137
+ (define-key mhc-prefix-map "|" 'mhc-import)
138
+ (define-key mhc-prefix-map "m" 'mhc-modify)
139
+ (define-key mhc-prefix-map "e" 'mhc-edit)
140
+ (define-key mhc-prefix-map "s" 'mhc-rescan-month)
141
+ (define-key mhc-prefix-map "d" 'mhc-delete)
142
+ (define-key mhc-prefix-map "c" 'mhc-set-default-category)
143
+ (define-key mhc-prefix-map "i" 'mhc-insert-schedule)
144
+ (define-key mhc-prefix-map "?" 'mhc-calendar)
145
+ (define-key mhc-prefix-map "t" 'mhc-calendar-toggle-insert-rectangle)
146
+ (define-key mhc-prefix-map "T" 'mhc-file-toggle-offline)
147
+ (define-key mhc-prefix-map "S" 'mhc-file-sync)
148
+ (define-key mhc-prefix-map "R" 'mhc-reset)
149
+ (define-key mhc-mode-map mhc-prefix-key mhc-prefix-map)
150
+ (cond
151
+ ((featurep 'xemacs)
152
+ (define-key mhc-mode-map [(button1)] 'mhc-calendar-mouse-goto-date)
153
+ (define-key mhc-mode-map [(button2)] 'mhc-calendar-mouse-goto-date-view))
154
+ (t
155
+ (define-key mhc-mode-map [mouse-1] 'mhc-calendar-mouse-goto-date)
156
+ (define-key mhc-mode-map [mouse-2] 'mhc-calendar-mouse-goto-date-view))))
157
+
158
+ (defvar mhc-mode nil "Non-nil when in mhc-mode.")
159
+
160
+ (defcustom mhc-mode-hook nil
161
+ "Hook run in when entering MHC mode."
162
+ :group 'mhc
163
+ :type 'hook)
164
+
165
+ ;; Avoid warning of byte-compiler.
166
+ (defvar mhc-mode-menu)
167
+ (eval-and-compile
168
+ (autoload 'easy-menu-add "easymenu"))
169
+
170
+ (defun mhc-mode (&optional arg) "\
171
+ \\<mhc-mode-map>
172
+ MHC is the mode for registering schdule directly from email.
173
+ Requres Mew or Wanderlust or Gnus.
174
+
175
+ Key assinment on mhc-mode.
176
+
177
+ \\[mhc-goto-this-month] Review the schedule of this month
178
+ \\[mhc-goto-next-month] Review the schedule of next month
179
+ \\[mhc-goto-prev-month] Review the schedule of previous month
180
+ \\[mhc-goto-month] Jump to your prefer month
181
+ \\[mhc-goto-date] Jump to your prefer date
182
+ \\[mhc-rescan-month] Rescan the buffer of the month
183
+ \\[mhc-goto-today] Move cursor to today (Only available reviewing this month)
184
+ \\[mhc-import] Register the reviewing mail to schdule
185
+ \\[mhc-delete] Delete the schdule on the cursor line
186
+ \\[mhc-set-default-category] Edit the schdule on the cursor line
187
+ \\[mhc-modify] Modify the schdule on the cursor line
188
+ \\[mhc-edit] Create new schdule file
189
+ \\[mhc-set-default-category] Change default category
190
+ \\[mhc-calendar] Display 3 months mini calendar
191
+ \\[mhc-calendar-toggle-insert-rectangle] Toggle 3 months calendar
192
+ \\[mhc-reset] Reset MHC
193
+
194
+ '\\[universal-argument]' prefix is available on using '\\[mhc-rescan-month]', '\\[mhc-goto-this-month]', '\\[mhc-goto-month]', '\\[mhc-goto-date]'
195
+ , it works to assign the category (see below).
196
+
197
+ The prefix arg '\\[mhc-goto-next-month]', '\\[mhc-goto-prev-month]' is also available and you can indicate
198
+ the number of months to forward/back.
199
+
200
+ Field names using by MHC.
201
+
202
+ X-SC-Category:
203
+ Space-seperated Keywords. You can set default category to scan.
204
+ You can also indicate keywords by typing '\\[mhc-rescan-month]', '\\[mhc-goto-this-month]', '\\[mhc-goto-month]', '\\[mhc-goto-date]' with C-u.
205
+ "
206
+ (interactive "P")
207
+ (make-local-variable 'mhc-mode)
208
+ (setq mhc-mode
209
+ (if (null arg)
210
+ (not mhc-mode)
211
+ (> (prefix-numeric-value arg) 0)))
212
+ (when (featurep 'xemacs)
213
+ (easy-menu-add mhc-mode-menu))
214
+ (force-mode-line-update)
215
+ (run-hooks 'mhc-mode-hook))
216
+
217
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
218
+ ;; lexical analyzer part for category.
219
+ ;;
220
+
221
+ (defsubst mhc-expr/new ()
222
+ (vector nil nil nil nil))
223
+
224
+ (defsubst mhc-expr/token (expr-obj) ;; literal
225
+ (aref expr-obj 0))
226
+ (defsubst mhc-expr/token-type (expr-obj) ;; symbolized
227
+ (aref expr-obj 1))
228
+ (defsubst mhc-expr/string (expr-obj) ;; currently parsing string.
229
+ (aref expr-obj 2))
230
+
231
+ (defsubst mhc-expr/set-token (expr-obj val)
232
+ (aset expr-obj 0 val))
233
+ (defsubst mhc-expr/set-token-type (expr-obj val)
234
+ (aset expr-obj 1 val))
235
+ (defsubst mhc-expr/set-string (expr-obj val)
236
+ (aset expr-obj 2 val))
237
+
238
+ (defconst mhc-expr-token-type-alist
239
+ '(
240
+ ("[^!&|()\t \n]+" . symbol)
241
+ ("!" . negop)
242
+ ("&&" . andop)
243
+ ("||" . orop)
244
+ ("(" . lparen)
245
+ (")" . rparen)))
246
+
247
+ ;; Eat one token from parsing string in obj.
248
+ (defun mhc-expr/gettoken (obj)
249
+ (let ((string (mhc-expr/string obj))
250
+ (token-alist mhc-expr-token-type-alist)
251
+ (token-type nil)
252
+ (token nil))
253
+ ;; delete leading white spaces.
254
+ (if (string-match "^[\t ]+" string)
255
+ (setq string (substring string (match-end 0))))
256
+ (while (and token-alist (not token-type))
257
+ (if (string-match (concat "^" (car (car token-alist))) string)
258
+ (setq token (substring string 0 (match-end 0))
259
+ string (substring string (match-end 0))
260
+ token-type (cdr (car token-alist))))
261
+ (setq token-alist (cdr token-alist)))
262
+
263
+ (mhc-expr/set-token obj token)
264
+ (mhc-expr/set-string obj string)
265
+ (mhc-expr/set-token-type obj token-type)
266
+ obj))
267
+
268
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
269
+ ;; recursive descent parser for category.
270
+ ;;
271
+
272
+ ;;
273
+ ;; expression -> term ("||" term)*
274
+ ;;
275
+ (defun mhc-expr/expression (obj)
276
+ (let ((ret (list (mhc-expr/term obj))))
277
+ (while (eq (mhc-expr/token-type obj) 'orop)
278
+ (mhc-expr/gettoken obj)
279
+ (setq ret (cons (mhc-expr/term obj) ret)))
280
+ (if (= 1 (length ret))
281
+ (car ret)
282
+ (cons 'or (nreverse ret)))))
283
+
284
+ ;;
285
+ ;; term -> factor ("&&" factor)*
286
+ ;;
287
+ (defun mhc-expr/term (obj)
288
+ (let ((ret (list (mhc-expr/factor obj))))
289
+ (while (eq (mhc-expr/token-type obj) 'andop)
290
+ (mhc-expr/gettoken obj)
291
+ (setq ret (cons (mhc-expr/factor obj) ret)))
292
+ (if (= 1 (length ret))
293
+ (car ret)
294
+ (cons 'and (nreverse ret)))))
295
+
296
+ ;;
297
+ ;; factor -> "!"* category_name || "(" expression ")"
298
+ ;;
299
+ (defun mhc-expr/factor (obj)
300
+ (let ((ret)
301
+ (neg-flag nil))
302
+ (while (eq (mhc-expr/token-type obj) 'negop)
303
+ (setq neg-flag (not neg-flag))
304
+ (mhc-expr/gettoken obj))
305
+ (cond
306
+ ;; symbol
307
+ ((eq (mhc-expr/token-type obj) 'symbol)
308
+ (setq ret (list 'mhc-schedule-in-category-p
309
+ 'schedule (mhc-expr/token obj)))
310
+ (mhc-expr/gettoken obj))
311
+ ;; ( expression )
312
+ ((eq (mhc-expr/token-type obj) 'lparen)
313
+ (mhc-expr/gettoken obj)
314
+ (setq ret (mhc-expr/expression obj))
315
+ (if (not (eq (mhc-expr/token-type obj) 'rparen))
316
+ (error "Syntax error."))
317
+ (mhc-expr/gettoken obj))
318
+ ;; error
319
+ (t
320
+ (error "Syntax error.")
321
+ ;; (error "Missing category name or `(' %s %s"
322
+ ;; mhc-expr-token mhc-expr-parsing-string)
323
+ ))
324
+ (if neg-flag (list 'not ret) ret)))
325
+
326
+ (defun mhc-expr-parse (string)
327
+ (let ((obj (mhc-expr/new)) (ret nil))
328
+ (if (or (not string) (string= string ""))
329
+ t
330
+ (mhc-expr/set-string obj string)
331
+ (mhc-expr/gettoken obj)
332
+ (setq ret (mhc-expr/expression obj))
333
+ (if (mhc-expr/token obj)
334
+ (error "Syntax Error.")
335
+ ret))))
336
+
337
+ (defun mhc-expr-compile (string)
338
+ (byte-compile
339
+ `(lambda (schedule)
340
+ ,(mhc-expr-parse string)
341
+ )))
342
+
343
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
344
+ ;;
345
+ ;; category
346
+ ;;
347
+ (defvar mhc-default-category nil)
348
+ (defvar mhc-default-category-predicate-sexp
349
+ (mhc-expr-compile ""))
350
+
351
+ (defvar mhc-default-category-hist nil)
352
+
353
+ (defun mhc-set-default-category ()
354
+ (interactive)
355
+ (setq mhc-default-category
356
+ (read-from-minibuffer "Default Category: "
357
+ (or mhc-default-category "")
358
+ nil nil 'mhc-default-category-hist))
359
+ (setq mhc-default-category-predicate-sexp
360
+ (mhc-expr-compile mhc-default-category))
361
+ (if (mhc-summary-buffer-p)
362
+ (mhc-rescan-month)))
363
+
364
+ ; (defun mhc-category-convert (lst)
365
+ ; (let (ret inv)
366
+ ; ;; preceding `!' means invert logic.
367
+ ; (if (and lst (string-match "^!" (car lst)))
368
+ ; (setq lst (cons (substring (car lst) (match-end 0)) (cdr lst))
369
+ ; inv t))
370
+ ; (cons inv lst)))
371
+
372
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
373
+ ;; goto-*
374
+
375
+ (defun mhc-goto-month (&optional date hide-private)
376
+ "*Show schedules of specified month.
377
+ If HIDE-PRIVATE, priavate schedules are suppressed."
378
+ (interactive
379
+ (list
380
+ (mhc-input-month "Month ")
381
+ (if mhc-default-hide-private-schedules
382
+ (not current-prefix-arg)
383
+ current-prefix-arg)))
384
+ (mhc-scan-month date
385
+ (mhc-summary-mailer-type)
386
+ mhc-default-category-predicate-sexp
387
+ hide-private))
388
+
389
+ (defvar mhc-goto-date-func 'mhc-goto-date-calendar)
390
+ ; or mhc-goto-date-summary
391
+ (defun mhc-goto-date (&optional hide-private)
392
+ "*Show schedules of specified date.
393
+ If HIDE-PRIVATE, private schedules are suppressed."
394
+ (interactive
395
+ (list
396
+ (if mhc-default-hide-private-schedules
397
+ (not current-prefix-arg)
398
+ current-prefix-arg)))
399
+ (let* ((owin (get-buffer-window (current-buffer)))
400
+ (buf (mhc-summary-get-import-buffer))
401
+ (win (if buf (get-buffer-window buf) nil))
402
+ date)
403
+ (save-excursion
404
+ (when win (select-window win))
405
+ (setq date (car (mhc-input-day "Date: " (mhc-date-now) (mhc-guess-date))))
406
+ (select-window owin))
407
+ (funcall mhc-goto-date-func date hide-private)))
408
+ (defun mhc-goto-date-calendar (date hide-private)
409
+ (mhc-calendar-goto-month date))
410
+ (defun mhc-goto-date-summary (date hide-private)
411
+ ;; XXX mhc-calendar-scanのパクリです
412
+ (mhc-goto-month date hide-private)
413
+ (goto-char (point-min))
414
+ (if (mhc-summary-search-date date)
415
+ (progn
416
+ (beginning-of-line)
417
+ (if (not (pos-visible-in-window-p (point)))
418
+ (recenter)))))
419
+
420
+ (defun mhc-goto-this-month (&optional hide-private)
421
+ "*Show schedules of this month.
422
+ If HIDE-PRIVATE, private schedules are suppressed."
423
+ (interactive
424
+ (list
425
+ (if mhc-default-hide-private-schedules
426
+ (not current-prefix-arg)
427
+ current-prefix-arg)))
428
+ (mhc-goto-month (mhc-date-now) hide-private))
429
+
430
+ (defun mhc-goto-next-month (&optional arg)
431
+ (interactive "p")
432
+ (mhc-goto-month (mhc-date-mm+
433
+ (or (mhc-current-date-month) (mhc-date-now)) arg)
434
+ mhc-default-hide-private-schedules))
435
+
436
+ (defun mhc-goto-next-year (&optional arg)
437
+ (interactive "p")
438
+ (mhc-goto-next-month (* (or arg 1) 12)))
439
+
440
+ (defun mhc-goto-prev-month (&optional arg)
441
+ (interactive "p")
442
+ (mhc-goto-next-month (- arg)))
443
+
444
+ (defun mhc-goto-prev-year (&optional arg)
445
+ (interactive "p")
446
+ (mhc-goto-next-year (- arg)))
447
+
448
+ (defun mhc-goto-today (&optional no-display)
449
+ "*Go to the line of today's schedule or first day of month.
450
+ Unless NO-DISPLAY, display it."
451
+ (interactive "P")
452
+ (let ((now (mhc-date-now))
453
+ (buf-date (mhc-current-date-month)))
454
+ (when buf-date
455
+ (goto-char (point-min))
456
+ (mhc-date-let now
457
+ (if (and (= yy (mhc-date-yy buf-date))
458
+ (= mm (mhc-date-mm buf-date)))
459
+ (when (mhc-summary-search-date now)
460
+ (forward-line 0)
461
+ (or (pos-visible-in-window-p (point))
462
+ (recenter))
463
+ (or no-display
464
+ (mhc-summary-display-article)))
465
+ (when (and mhc-use-wide-scope
466
+ (mhc-summary-search-date (mhc-date-mm-first buf-date)))
467
+ (forward-line 0)
468
+ (or (pos-visible-in-window-p (point))
469
+ (recenter))
470
+ (or no-display
471
+ (mhc-summary-display-article)))))
472
+ ;; Emacs-21.3.50 something wrong
473
+ (beginning-of-line))))
474
+
475
+ (defun mhc-rescan-month (&optional hide-private)
476
+ "*Rescan schedules of this buffer.
477
+ If HIDE-PRIVATE, private schedules are suppressed."
478
+ (interactive
479
+ (list
480
+ (if mhc-default-hide-private-schedules
481
+ (not current-prefix-arg)
482
+ current-prefix-arg)))
483
+ (move-to-column 1)
484
+ (let ((line (+ (count-lines (point-min) (point))
485
+ (if (= (current-column) 0) 1 0))))
486
+ (mhc-scan-month (or (mhc-current-date-month) (mhc-date-now))
487
+ (mhc-summary-mailer-type)
488
+ mhc-default-category-predicate-sexp
489
+ hide-private)
490
+ (goto-char (point-min))
491
+ (if (eq selective-display t)
492
+ (re-search-forward "[\n\C-m]" nil 'end (1- line))
493
+ (forward-line (1- line))))
494
+ (beginning-of-line))
495
+
496
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
497
+ ;; make scan form.
498
+
499
+ (defvar mhc-face-week-color-paint-thick nil)
500
+
501
+ (defvar mhc-summary-buffer-current-date-month nil
502
+ "Indicate summary buffer's month. It is also used by mhc-summary-buffer-p")
503
+ (make-variable-buffer-local 'mhc-summary-buffer-current-date-month)
504
+
505
+ (defun mhc-expand-date-scope-backward (date scope)
506
+ "Expand date scope backward involving the whole first week of month.
507
+ DATE can be any date of the target month.
508
+ SCOPE is one of:
509
+ + 'week: Expand to involve the whole first week of month.
510
+ + 'wide: Just like 'week, but if 'week does not expand nothing,
511
+ it takes 7 days.
512
+ + number: Expand N days backward."
513
+ (let ((edge-date (mhc-date-mm-first date)))
514
+ (cond
515
+ ((integerp scope)
516
+ (mhc-date- edge-date scope))
517
+ ((eq scope 'week)
518
+ (mhc-date-ww-first edge-date mhc-start-day-of-week))
519
+ ((eq scope 'wide)
520
+ (mhc-date-ww-first (mhc-date-- edge-date) mhc-start-day-of-week)))))
521
+
522
+ (defun mhc-expand-date-scope-forward (date scope)
523
+ "Expand date scope forward involving the whole last week of month.
524
+ DATE can be any date of the target month.
525
+ SCOPE is one of:
526
+ + 'week: Expand to involve the whole last week of month.
527
+ + 'wide: Just like 'week, but if 'week does not expand nothing,
528
+ it takes 7 days.
529
+ + number: Expand N days forward."
530
+ (let ((edge-date (mhc-date-mm-last date)))
531
+ (cond
532
+ ((integerp scope)
533
+ (mhc-date+ edge-date scope))
534
+ ((eq scope 'week)
535
+ (mhc-date-ww-last edge-date mhc-start-day-of-week))
536
+ ((eq scope 'wide)
537
+ (mhc-date-ww-last (mhc-date++ edge-date) mhc-start-day-of-week)))))
538
+
539
+ (defun mhc-scan-month (date mailer category-predicate secret)
540
+ "Make summary buffer for a month indicated by DATE.
541
+ DATE can be any date of the target month.
542
+ If MAILER is 'direct, insert scanned result into current buffer.
543
+ CATEGORY-PREDICATE must be a function that can take one mhc-schedule
544
+ argument and return a boolean value indicates opacity of the article.
545
+ If SECRET is non-nil, hide articles those categories are
546
+ listed in ``mhc-category-as-private''."
547
+ (let* ((from (mhc-date-mm-first date))
548
+ (to (mhc-date-mm-last date))
549
+ (today (mhc-date-now))
550
+ ;; need three months for mini-calendar
551
+ (dayinfo-list (mhc-db-scan (mhc-date-mm-- from) (mhc-date-mm++ to))))
552
+ (unless (eq 'direct mailer)
553
+ (mhc-summary-generate-buffer date mailer)
554
+ (setq mhc-summary-buffer-current-date-month
555
+ (mhc-date-mm-first date)))
556
+ (when mhc-use-wide-scope
557
+ (setq from (mhc-expand-date-scope-backward date mhc-use-wide-scope))
558
+ (setq to (mhc-expand-date-scope-forward date mhc-use-wide-scope)))
559
+ (message "%s" (mhc-date-format date "Scanning %04d/%02d..." yy mm))
560
+ (mhc-summary-make-contents
561
+ dayinfo-list
562
+ from to mailer category-predicate secret)
563
+ (unless (eq 'direct mailer)
564
+ (when mhc-insert-calendar
565
+ (mhc-calendar-insert-rectangle-at
566
+ date
567
+ (- (mhc-misc-get-width) mhc-calendar-width)
568
+ mhc-vertical-calendar-length
569
+ dayinfo-list))
570
+ (mhc-summary-mode-setup date mailer)
571
+ (mhc-mode 1)
572
+ (setq mhc-summary-buffer-current-date-month
573
+ (mhc-date-mm-first date))
574
+ (mhc-goto-today t)
575
+ (message "%s" (mhc-date-format date "Scanning %04d/%02d...done" yy mm)))))
576
+
577
+ (defun mhc-search (string &optional subject-only)
578
+ "Search events by STRING.
579
+ If SUBJECT-ONLY is non-nil, it will search only on X-SC-Subject:"
580
+ (interactive "sSearch: \nP")
581
+ (let* ((match (mhc-db-search :subject string :body (unless subject-only string))))
582
+ (if (null match)
583
+ (message "No match")
584
+ (mhc-scan match))))
585
+
586
+ (defun mhc-scan (events &optional insert-current-buffer clip-from clip-to)
587
+ "Create mhc-summary buffer using EVENTS list.
588
+ If INSERT-CURRENT-BUFFER is non-nil, insert contents in the current buffer.
589
+ if CLIP-FROM and CLIP-TO are specified, clip EVENTS by date using these two params."
590
+ (unless insert-current-buffer
591
+ (mhc-summary-generate-buffer "MHC SEARCH"))
592
+ (message "Listing MHC events...")
593
+ (mhc-summary-make-contents events clip-from clip-to)
594
+ (mhc-summary-mode)
595
+ (goto-char (point-min))
596
+ (message "Listing MHC events...done"))
597
+
598
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
599
+ ;; import, edit, delete, modify
600
+
601
+ (defcustom mhc-input-sequences '(date time subject location category recurrence-tag alarm)
602
+ "*Sequence of the inputs."
603
+ :group 'mhc
604
+ :type '(repeat (choice (const :tag "Date" date)
605
+ (const :tag "Time" time)
606
+ (const :tag "Subject" subject)
607
+ (const :tag "Location" location)
608
+ (const :tag "Category" category)
609
+ (const :tag "Recurrence tag" recurrence-tag)
610
+ (const :tag "Alarm" alarm))))
611
+
612
+ (defun mhc-edit (&optional import-buffer)
613
+ "Edit a new schedule.
614
+ If optional argument IMPORT-BUFFER is specified, import its content.
615
+ Returns t if the importation was succeeded."
616
+ (interactive
617
+ (if current-prefix-arg
618
+ (list (get-buffer (read-buffer "Import buffer: "
619
+ (current-buffer))))))
620
+ (let ((draft-buffer (generate-new-buffer mhc-draft-buffer-name))
621
+ (current-date (or (mhc-current-date) (mhc-calendar-get-date) (mhc-date-now)))
622
+ (succeed t)
623
+ msgp date time subject location category recurrence-tag priority alarm)
624
+ (and (called-interactively-p 'interactive)
625
+ (mhc-window-push))
626
+ (set-buffer draft-buffer)
627
+ (if import-buffer
628
+ (progn
629
+ (insert-buffer-substring-no-properties
630
+ (if (consp import-buffer)
631
+ (cdr import-buffer)
632
+ import-buffer))
633
+ (mhc-header-narrowing
634
+ (setq msgp (or (mhc-header-get-value "from")
635
+ (mhc-header-get-value "x-sc-subject")))
636
+ (mhc-header-delete-header
637
+ (concat "^\\("
638
+ (mhc-regexp-opt mhc-draft-unuse-hdr-list)
639
+ "\\)")
640
+ 'regexp))
641
+ (mhc-highlight-message)
642
+ (switch-to-buffer draft-buffer t)))
643
+ (condition-case ()
644
+ (if import-buffer
645
+ (progn
646
+ (delete-other-windows)
647
+ (goto-char (point-min))
648
+ (if (y-or-n-p "Do you want to import this article? ")
649
+ (let* ((original (with-current-buffer
650
+ (if (consp import-buffer)
651
+ (cdr import-buffer)
652
+ import-buffer)
653
+ (mhc-parse-buffer)))
654
+ (schedule (car (mhc-record-schedules original)))
655
+ (inputs (copy-sequence mhc-input-sequences))
656
+ input)
657
+ (while (setq input (car inputs))
658
+ (setq inputs (delq input inputs))
659
+ (cond
660
+ ((eq input 'date)
661
+ ;; input date
662
+ (setq date
663
+ (mhc-input-day "Date: "
664
+ current-date
665
+ (mhc-guess-date))))
666
+ ((eq input 'time)
667
+ ;; input time
668
+ (setq time
669
+ (mhc-input-time "Time: "
670
+ (mhc-schedule-time-as-string
671
+ schedule)
672
+ (mhc-guess-time
673
+ (mhc-minibuf-candidate-nth-begin)))))
674
+ ((eq input 'subject)
675
+ ;; input subject
676
+ (setq subject
677
+ (mhc-input-subject
678
+ "Subject: "
679
+ (mhc-misc-sub
680
+ (or (mhc-record-subject original)
681
+ (mhc-header-narrowing
682
+ (mhc-header-get-value "subject")))
683
+ "^\\(Re:\\)? *\\(\\[[^\]]+\\]\\)? *"
684
+ ""))))
685
+ ((eq input 'location)
686
+ ;; input location
687
+ (setq location
688
+ (mhc-input-location
689
+ "Location: "
690
+ (mhc-schedule-location schedule))))
691
+ ((eq input 'category)
692
+ ;; input category
693
+ (setq category
694
+ (mhc-input-category
695
+ "Category: "
696
+ (mhc-schedule-categories-as-string schedule))))
697
+ ;; input recurrence tag
698
+ ((eq input 'recurrence-tag)
699
+ (setq recurrence-tag
700
+ (mhc-input-recurrence-tag
701
+ "Recurrence Tag: "
702
+ (mhc-schedule-recurrence-tag-as-string schedule))))
703
+ ;; input alarm
704
+ ((eq input 'alarm)
705
+ (if mhc-ask-alarm
706
+ (setq alarm
707
+ (mhc-input-alarm
708
+ "Alarm: "
709
+ mhc-default-alarm))))))
710
+ ;;
711
+ (setq priority (mhc-schedule-priority schedule)))
712
+ ;; Answer was no.
713
+ (message "") ; flush minibuffer.
714
+ (and (called-interactively-p 'interactive)
715
+ (mhc-window-pop))
716
+ (setq succeed nil)
717
+ (kill-buffer draft-buffer)))
718
+ ;; No import (it succeeds).
719
+ (let ((inputs (copy-sequence mhc-input-sequences))
720
+ input)
721
+ (while (setq input (car inputs))
722
+ (setq inputs (delq input inputs))
723
+ (cond
724
+ ((eq input 'date)
725
+ (setq date (mhc-input-day "Date: " current-date)))
726
+ ((eq input 'time)
727
+ (setq time (mhc-input-time "Time: ")))
728
+ ((eq input 'subject)
729
+ (setq subject (mhc-input-subject "Subject: ")))
730
+ ((eq input 'location)
731
+ (setq location (mhc-input-location "Location: ")))
732
+ ((eq input 'category)
733
+ (setq category (mhc-input-category "Category: ")))
734
+ ((eq input 'recurrence-tag)
735
+ (setq recurrence-tag (mhc-input-recurrence-tag "Recurrence Tag: " (or subject ""))))
736
+ ((eq input 'alarm)
737
+ (if mhc-ask-alarm
738
+ (setq alarm (mhc-input-alarm "Alarm: " mhc-default-alarm))))))))
739
+ ;; Quit.
740
+ (quit
741
+ (and (called-interactively-p 'interactive)
742
+ (mhc-window-pop))
743
+ (setq succeed nil)
744
+ (kill-buffer draft-buffer)))
745
+ (if succeed
746
+ (progn
747
+ (switch-to-buffer draft-buffer t)
748
+ (set-buffer draft-buffer)
749
+ (if (and import-buffer msgp)
750
+ (if (consp import-buffer)
751
+ (mhc-draft-reedit-buffer (car import-buffer) 'original)
752
+ ;; Delete candidate overlay if exists.
753
+ (if mhc-minibuf-candidate-overlay
754
+ (delete-overlay mhc-minibuf-candidate-overlay))
755
+ ;; Already imported to current buffer.
756
+ (mhc-draft-reedit-buffer (current-buffer)))
757
+ ;; Delete candidate overlay if exists.
758
+ (if mhc-minibuf-candidate-overlay
759
+ (delete-overlay mhc-minibuf-candidate-overlay))
760
+ (mhc-draft-setup-new))
761
+ (mhc-header-narrowing
762
+ (mhc-header-delete-header
763
+ (concat "^\\("
764
+ (mhc-regexp-opt (mhc-header-list))
765
+ "\\)")
766
+ 'regexp))
767
+ (goto-char (point-min))
768
+ (insert "X-SC-Subject: " subject
769
+ "\nX-SC-Location: " location
770
+ "\nX-SC-Day: "
771
+ (mapconcat
772
+ (lambda (day)
773
+ (mhc-date-format day "%04d%02d%02d" yy mm dd))
774
+ date " ")
775
+ "\nX-SC-Time: "
776
+ (if time
777
+ (let ((begin (car time))
778
+ (end (nth 1 time)))
779
+ (concat
780
+ (if begin (mhc-time-to-string begin) "")
781
+ (if end (concat "-" (mhc-time-to-string end)) "")))
782
+ "")
783
+ "\nX-SC-Category: "
784
+ (mapconcat (function capitalize) category " ")
785
+ "\nX-SC-Priority: " (if priority
786
+ (number-to-string priority)
787
+ "")
788
+ "\nX-SC-Recurrence-Tag: " recurrence-tag
789
+ "\nX-SC-Cond: "
790
+ "\nX-SC-Duration: "
791
+ "\nX-SC-Alarm: " (or alarm "")
792
+ "\nX-SC-Record-Id: " (mhc-record-create-id)
793
+ "\nX-SC-Sequence: 0\n")
794
+ (goto-char (point-min))
795
+ (mhc-draft-mode)
796
+ succeed))))
797
+
798
+ (defcustom mhc-default-import-original-article nil
799
+ "*If non-nil value, import a schedule with MIME attachements."
800
+ :group 'mhc
801
+ :type 'boolean)
802
+
803
+ (defun mhc-import (&optional get-original)
804
+ "Import a schedule from the current article.
805
+ The default action of this command is to import a schedule from the
806
+ current article without MIME attachements. If you want to import a
807
+ schedule including MIME attachements, call this command with a prefix
808
+ argument GET-ORIGINAL.
809
+ Set non-nil to `mhc-default-import-original-article', and
810
+ the default action of this command is changed to the latter."
811
+ (interactive
812
+ (list (if mhc-default-import-original-article
813
+ (not current-prefix-arg)
814
+ current-prefix-arg)))
815
+ (mhc-window-push)
816
+ (unless (mhc-edit (mhc-summary-get-import-buffer get-original))
817
+ ;; failed.
818
+ (mhc-window-pop)))
819
+
820
+ (defun mhc-import-from-region (beg end)
821
+ "Import a schedule from region BEG END."
822
+ (interactive "r")
823
+ (save-restriction
824
+ (narrow-to-region beg end)
825
+ (let ((str (buffer-substring beg end)))
826
+ (mhc-import)
827
+ (goto-char (point-max))
828
+ (insert str)
829
+ (goto-char (point-min)))))
830
+
831
+ (defun mhc-delete ()
832
+ "Delete the current schedule."
833
+ (interactive)
834
+ (mhc-delete-file (mhc-summary-record)))
835
+
836
+ (defcustom mhc-delete-file-hook nil
837
+ "Normal hook run after mhc-delete-file."
838
+ :group 'mhc
839
+ :type 'hook)
840
+
841
+ (defun mhc-delete-file (record)
842
+ (interactive)
843
+ (if (not (and record (file-exists-p (mhc-record-name record))))
844
+ (message "File does not exist (%s)." (mhc-record-name record))
845
+ (if (not (y-or-n-p (format "Do you delete %s ?"
846
+ (mhc-record-subject-as-string record))))
847
+ (message "Never mind..")
848
+ (if (and
849
+ (mhc-record-occur-multiple-p record)
850
+ (not (y-or-n-p
851
+ (format
852
+ "%s has multiple occurrences. Delete all(=y) or one(=n) ?"
853
+ (mhc-record-subject-as-string record)))))
854
+ (mhc-db-add-exception-rule
855
+ record
856
+ (or (mhc-current-date)
857
+ (mhc-calendar-view-date)))
858
+ (mhc-db-delete-file record))
859
+ (or (and (mhc-summary-buffer-p)
860
+ (mhc-rescan-month mhc-default-hide-private-schedules))
861
+ (and (mhc-calendar-p) (mhc-calendar-rescan)))
862
+ (run-hooks 'mhc-delete-file-hook))))
863
+
864
+ (defun mhc-modify ()
865
+ "Modify the current schedule."
866
+ (interactive)
867
+ (mhc-modify-file (mhc-summary-filename)))
868
+
869
+ (defcustom mhc-browse-x-url-function 'browse-url
870
+ "*A function to browse URL."
871
+ :group 'mhc
872
+ :type 'function)
873
+
874
+ (defun mhc-browse-x-url ()
875
+ "Browse X-URL field."
876
+ (interactive)
877
+ (let ((filename (mhc-summary-filename))
878
+ url)
879
+ (with-temp-buffer
880
+ (insert-file-contents filename)
881
+ (if (setq url (mhc-header-narrowing
882
+ (or (mhc-header-get-value "x-uri")
883
+ (mhc-header-get-value "x-url"))))
884
+ (progn
885
+ (funcall mhc-browse-x-url-function url)
886
+ (message "X-URL browser started."))
887
+ (message "No X-URL field.")))))
888
+
889
+ (defun mhc-modify-file (file)
890
+ (if (and (stringp file) (file-exists-p file))
891
+ (let* ((name (format
892
+ "*mhc draft %s*"
893
+ (file-name-nondirectory file)))
894
+ (buffer (get-buffer name)))
895
+ (if (buffer-live-p buffer)
896
+ (progn
897
+ (message "Specified file(%s) has already been opened." file)
898
+ (switch-to-buffer-other-window buffer))
899
+ (mhc-window-push)
900
+ (set-buffer (setq buffer (get-buffer-create name)))
901
+ (mhc-draft-reedit-file file)
902
+ (set-buffer-modified-p nil)
903
+ (switch-to-buffer-other-window buffer)
904
+ (goto-char (point-min))
905
+ (mhc-draft-mode)
906
+ (set (make-local-variable 'mhc-draft-buffer-file-name) file)))
907
+ (message "Specified file(%s) does not exist." file)))
908
+
909
+
910
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
911
+ ;;
912
+ ;; Window stack
913
+ ;;
914
+
915
+ (defvar mhc-window-stack nil)
916
+
917
+ (defun mhc-window-push ()
918
+ (interactive)
919
+ (setq mhc-window-stack
920
+ (cons (current-window-configuration) mhc-window-stack)))
921
+
922
+ (defun mhc-window-pop ()
923
+ (interactive)
924
+ (if mhc-window-stack
925
+ (set-window-configuration (car-safe mhc-window-stack)))
926
+ (setq mhc-window-stack (cdr-safe mhc-window-stack)))
927
+
928
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
929
+ ;;
930
+ ;; (Category . (parent-face fg bg))
931
+ ;;
932
+
933
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
934
+ ;; manipulate data from mhc-summary-buffer.
935
+
936
+ (defconst mhc-summary-day-regex "\\([^|]+| +\\)?[0-9]+/\\([0-9]+\\)")
937
+
938
+ (defun mhc-summary-buffer-p (&optional buffer)
939
+ (if buffer
940
+ (set-buffer buffer))
941
+ mhc-summary-buffer-current-date-month)
942
+
943
+ (defun mhc-current-date ()
944
+ (when (mhc-summary-buffer-p)
945
+ (let ((dayinfo (get-text-property (point) 'mhc-dayinfo)))
946
+ (or (and dayinfo (mhc-day-date dayinfo))
947
+ (save-excursion
948
+ (end-of-line)
949
+ (while (and (not (bobp))
950
+ (null dayinfo))
951
+ (or (setq dayinfo (get-text-property (point) 'mhc-dayinfo))
952
+ (forward-char -1)))
953
+ (and dayinfo (mhc-day-date dayinfo)))))))
954
+
955
+ (defun mhc-current-date-month ()
956
+ mhc-summary-buffer-current-date-month)
957
+
958
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
959
+ ;; misc.
960
+
961
+ ;;
962
+ ;; Convinient function when you want to insert your schedule into an
963
+ ;; editing buffer.
964
+ ;;
965
+ (defun mhc-insert-schedule (&optional hide-private)
966
+ (interactive "P")
967
+ (set-mark (point))
968
+ (mhc-scan-month (mhc-input-month "Month ")
969
+ 'direct ;; insert into current buffer.
970
+ mhc-default-category-predicate-sexp
971
+ hide-private)
972
+ (exchange-point-and-mark))
973
+
974
+ (defun mhc-view-file ()
975
+ "View the schedule on the current line in View mode in another window."
976
+ (interactive)
977
+ (let ((path (mhc-summary-filename)))
978
+ (view-file-other-window path)))
979
+
980
+
981
+ ;;; Temporary buffers
982
+
983
+ (defvar mhc-tmp-buffer-list nil)
984
+
985
+ (defun mhc-get-buffer-create (name)
986
+ "Return NAME buffer for temporary use of MHC."
987
+ (let ((buf (get-buffer name)))
988
+ (or (and buf (buffer-name buf))
989
+ (progn
990
+ (setq buf (get-buffer-create name)
991
+ mhc-tmp-buffer-list (cons buf mhc-tmp-buffer-list))
992
+ (buffer-disable-undo buf)))
993
+ buf))
994
+
995
+ (defun mhc-kill-all-buffers ()
996
+ "Kill all buffers for temporary use of MHC."
997
+ (while mhc-tmp-buffer-list
998
+ (if (buffer-name (car mhc-tmp-buffer-list))
999
+ (kill-buffer (car mhc-tmp-buffer-list)))
1000
+ (setq mhc-tmp-buffer-list
1001
+ (cdr mhc-tmp-buffer-list))))
1002
+
1003
+
1004
+ ;;; Setup and exit
1005
+
1006
+ (defcustom mhc-setup-hook nil
1007
+ "Run hook after mhc-setup."
1008
+ :group 'mhc
1009
+ :type 'hook)
1010
+
1011
+ (defvar mhc-setup-p nil)
1012
+
1013
+ (defun mhc-setup ()
1014
+ (unless mhc-setup-p
1015
+ (condition-case nil
1016
+ (progn
1017
+ (or (featurep 'easymenu) (require 'easymenu))
1018
+ (easy-menu-define mhc-mode-menu
1019
+ mhc-mode-map
1020
+ "Menu used in mhc mode."
1021
+ mhc-mode-menu-spec)
1022
+ (easy-menu-define mhc-calendar-mode-menu
1023
+ mhc-calendar-mode-map
1024
+ "Menu used in mhc calendar mode."
1025
+ mhc-calendar-mode-menu-spec))
1026
+ (error nil))
1027
+ (or (assq 'mhc-mode minor-mode-alist)
1028
+ (setq minor-mode-alist
1029
+ (cons (list 'mhc-mode (mhc-file-line-status))
1030
+ minor-mode-alist)))
1031
+ (or (assq 'mhc-mode minor-mode-map-alist)
1032
+ (setq minor-mode-map-alist
1033
+ (cons (cons 'mhc-mode mhc-mode-map)
1034
+ minor-mode-map-alist)))
1035
+ (mhc-face-setup)
1036
+ (mhc-calendar-setup)
1037
+ (mhc-file-setup)
1038
+ (setq mhc-default-category-predicate-sexp
1039
+ (mhc-expr-compile mhc-default-category))
1040
+ (and (mhc-use-icon-p) (mhc-icon-setup))
1041
+ (and mhc-calendar-link-hnf (mhc-calendar-hnf-face-setup))
1042
+ (mhc-summary-line-inserter-setup)
1043
+ (mhc-guess-location-setup)
1044
+ (autoload 'mhc-ps "mhc-ps" "*Create PostScript calendar with selected method." t)
1045
+ (autoload 'mhc-ps-preview "mhc-ps" "*Preview PostScript calendar." t)
1046
+ (autoload 'mhc-ps-print "mhc-ps" "*Print PostScript calendar." t)
1047
+ (autoload 'mhc-ps-save "mhc-ps" "*Save PostScript calendar." t)
1048
+ (autoload 'mhc-ps-insert-buffer "mhc-ps" "*Insert PostScript calendar." t)
1049
+ (setq mhc-setup-p t)
1050
+ (run-hooks 'mhc-setup-hook)))
1051
+
1052
+ (defun mhc-reset ()
1053
+ "Reset MHC."
1054
+ (interactive)
1055
+ (message "MHC resetting...")
1056
+ (mhc-face-setup)
1057
+ (mhc-calendar-setup)
1058
+ (and (mhc-use-icon-p) (mhc-icon-setup))
1059
+ (and mhc-calendar-link-hnf (mhc-calendar-hnf-face-setup))
1060
+ (mhc-summary-line-inserter-setup)
1061
+ (mhc-guess-location-setup)
1062
+ (or (and (mhc-summary-buffer-p)
1063
+ (mhc-rescan-month mhc-default-hide-private-schedules))
1064
+ (and (mhc-calendar-p) (mhc-calendar-rescan)))
1065
+ (message "MHC resetting...done"))
1066
+
1067
+ (defcustom mhc-exit-hook nil
1068
+ "Run hook after mhc-exit."
1069
+ :group 'mhc
1070
+ :type 'hook)
1071
+
1072
+ (defun mhc-exit ()
1073
+ (setq mhc-setup-p nil)
1074
+ (mhc-file-exit)
1075
+ (mhc-kill-all-buffers)
1076
+ (run-hooks 'mhc-exit-hook))
1077
+
1078
+ (defun mhc-version ()
1079
+ "Show mhc version."
1080
+ (interactive)
1081
+ (message mhc-version))
1082
+
1083
+ ;;; Copyright Notice:
1084
+
1085
+ ;; Copyright (C) 1999, 2000 Yoshinari Nomura. All rights reserved.
1086
+ ;; Copyright (C) 2000 MHC developing team. All rights reserved.
1087
+
1088
+ ;; Redistribution and use in source and binary forms, with or without
1089
+ ;; modification, are permitted provided that the following conditions
1090
+ ;; are met:
1091
+ ;;
1092
+ ;; 1. Redistributions of source code must retain the above copyright
1093
+ ;; notice, this list of conditions and the following disclaimer.
1094
+ ;; 2. Redistributions in binary form must reproduce the above copyright
1095
+ ;; notice, this list of conditions and the following disclaimer in the
1096
+ ;; documentation and/or other materials provided with the distribution.
1097
+ ;; 3. Neither the name of the team nor the names of its contributors
1098
+ ;; may be used to endorse or promote products derived from this software
1099
+ ;; without specific prior written permission.
1100
+ ;;
1101
+ ;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS''
1102
+ ;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1103
+ ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1104
+ ;; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
1105
+ ;; THE TEAM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
1106
+ ;; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1107
+ ;; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1108
+ ;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1109
+ ;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
1110
+ ;; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1111
+ ;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
1112
+ ;; OF THE POSSIBILITY OF SUCH DAMAGE.
1113
+
1114
+ ;;; mhc.el ends here