diff -Nru mhc-1.1.1+0.20171016/bin/mhc mhc-1.1.1+0.20180314/bin/mhc --- mhc-1.1.1+0.20171016/bin/mhc 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/bin/mhc 2018-03-14 07:04:13.000000000 +0000 @@ -274,7 +274,7 @@ return 1 end - errors = Mhc::Event.validate(File.open(full_path).read) + errors = Mhc::Event.validate(File.open(full_path) {|f| f.read}) string = "" exit_on_error do diff -Nru mhc-1.1.1+0.20171016/debian/changelog mhc-1.1.1+0.20180314/debian/changelog --- mhc-1.1.1+0.20171016/debian/changelog 2018-01-24 11:19:06.000000000 +0000 +++ mhc-1.1.1+0.20180314/debian/changelog 2018-03-15 14:49:19.000000000 +0000 @@ -1,3 +1,9 @@ +mhc (1.1.1+0.20180314-1) unstable; urgency=medium + + * New upstream version 1.1.1+0.20180314 + + -- Tatsuya Kinoshita Thu, 15 Mar 2018 23:49:19 +0900 + mhc (1.1.1+0.20171016-1) unstable; urgency=medium * New upstream version 1.1.1+0.20171016 diff -Nru mhc-1.1.1+0.20171016/emacs/mhc-db.el mhc-1.1.1+0.20180314/emacs/mhc-db.el --- mhc-1.1.1+0.20171016/emacs/mhc-db.el 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/emacs/mhc-db.el 2018-03-14 07:04:13.000000000 +0000 @@ -80,32 +80,33 @@ nosort category))) -(defun mhc-db-add-record-from-buffer (record buffer &optional force-refile) - (let* ((slot (mhc-logic-record-to-slot record)) - (directory (and slot - (file-name-as-directory - (expand-file-name - "spool" (mhc-config-base-directory))))) - (old-record)) - (unless slot (error "Cannot get schedule slot")) - (if (mhc-record-name record) - ;; Modifying existing record - (setq old-record record) - ;; Creating new record - (mhc-record-set-name record (mhc-misc-get-new-path directory record))) - (if (or force-refile - (y-or-n-p (format - "Refile %s to %s " - (or (mhc-record-name old-record) "it") - (mhc-record-name record)))) - (progn - (mhc-record-write-buffer record buffer old-record) - (if (and old-record - (not (eq record old-record))) - (let* ((dir (file-name-directory - (directory-file-name - (mhc-record-name old-record))))) - (mhc-misc-touch-directory dir))) +(defun mhc-db-record-path-from-buffer (buffer) + "Return file path in MHC spool bound to BUFFER. +File path is taken from X-SC-Record-Id field." + (with-current-buffer buffer + (let ((spool-directory (file-name-as-directory + (expand-file-name + "spool" (mhc-config-base-directory)))) + (record-id (mhc-draft-record-id))) + (expand-file-name (concat record-id ".mhc") spool-directory)))) + +(defun mhc-db-add-record-from-buffer (buffer &optional allow-overwrite) + "Add current mhc-draft BUFFER to MHC db. +If optional ALLOW-OVERWRITE is non-nil, do not ask overwrite." + (let* ((path (mhc-db-record-path-from-buffer buffer)) + (directory (file-name-directory path)) + (overwriting (file-exists-p path))) + (if (or (not overwriting) + allow-overwrite + (y-or-n-p (format "Overwrite existing %s? " path))) + (with-current-buffer buffer + (mhc-draft-increment-sequence) + (mhc-draft-translate) + (mhc-file-make-directory directory) + (mhc-write-region-as-coding-system + mhc-default-coding-system + (point-min) (point-max) path nil 'nomsg) + (set-buffer-modified-p nil) (mhc-misc-touch-directory directory) t)))) diff -Nru mhc-1.1.1+0.20171016/emacs/mhc-draft.el mhc-1.1.1+0.20180314/emacs/mhc-draft.el --- mhc-1.1.1+0.20171016/emacs/mhc-draft.el 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/emacs/mhc-draft.el 2018-03-14 07:04:13.000000000 +0000 @@ -213,22 +213,40 @@ (mhc-header-put-value xsc "")))) xsc-headers)))) +(defun mhc-draft-record-id () + "Get X-SC-Record-Id header value in draft buffer." + (mhc-header-narrowing + (mhc-header-get-value "x-sc-record-id"))) + +(defun mhc-draft-validate-buffer (&optional buffer) + "Validate mhc draft BUFFER. +If BUFFER is omitted, current buffer will be validated." + (interactive) + (let ((validation (mhc-process-send-command-with-buffer + "validate --format=emacs" + (or buffer (current-buffer))))) + (if (and (stringp validation) + (string-match "^OK" validation)) + (message "Validation passed.") + ;; \\' means end of string (not end of each line) + (error "ERROR: %s" (replace-regexp-in-string "[.\r\n]+\\'" "" validation))))) + (defun mhc-draft-finish () "Add current draft as a schedule." (interactive) - (let ((record - (mhc-parse-buffer (mhc-record-new mhc-draft-buffer-file-name) - 'strict))) - (mhc-calendar-input-exit) - (if (mhc-db-add-record-from-buffer record (current-buffer) - (not (called-interactively-p 'interactive))) - (progn - (kill-buffer (current-buffer)) - (mhc-window-pop) - (or (and (mhc-summary-buffer-p) - (mhc-rescan-month mhc-default-hide-private-schedules)) - (and (mhc-calendar-p) (mhc-calendar-rescan))) - (run-hooks 'mhc-draft-finish-hook))))) + (mhc-draft-validate-buffer) + (mhc-calendar-input-exit) + (if (mhc-db-add-record-from-buffer + (current-buffer) + (not (called-interactively-p 'interactive))) + (progn + (kill-buffer (current-buffer)) + (mhc-window-pop) + (or (and (mhc-summary-buffer-p) + (mhc-rescan-month mhc-default-hide-private-schedules)) + (and (mhc-calendar-p) (mhc-calendar-rescan))) + (run-hooks 'mhc-draft-finish-hook) + (message "Successfully registered.")))) (provide 'mhc-draft) diff -Nru mhc-1.1.1+0.20171016/emacs/mhc.el mhc-1.1.1+0.20180314/emacs/mhc.el --- mhc-1.1.1+0.20171016/emacs/mhc.el 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/emacs/mhc.el 2018-03-14 07:04:13.000000000 +0000 @@ -371,10 +371,15 @@ (if mhc-default-hide-private-schedules (not current-prefix-arg) current-prefix-arg))) - (mhc-scan-month date - 'mhc-mua - mhc-default-category-predicate-sexp - hide-private)) + (let ((name (if (and (mhc-summary-buffer-p) + (not (string-match + "^[0-9][0-9][0-9][0-9]-[0-9][0-9]$" (buffer-name)))) + (buffer-name)))) + (mhc-scan-month date + 'mhc-mua + mhc-default-category-predicate-sexp + hide-private + name))) (defvar mhc-goto-date-func 'mhc-goto-date-calendar) ; or mhc-goto-date-summary @@ -524,21 +529,22 @@ ((eq scope 'wide) (mhc-date-ww-last (mhc-date++ edge-date) mhc-start-day-of-week))))) -(defun mhc-scan-month (date mailer category-predicate secret) +(defun mhc-scan-month (date mailer category-predicate secret &optional name) "Make summary buffer for a month indicated by DATE. DATE can be any date of the target month. If MAILER is 'direct, insert scanned result into current buffer. CATEGORY-PREDICATE must be a function that can take one mhc-schedule argument and return a boolean value indicates opacity of the article. If SECRET is non-nil, hide articles those categories are -listed in ``mhc-category-as-private''." +listed in ``mhc-category-as-private''. +If optional NAME is non-nil, created smmary buffer has the name." (let* ((from (mhc-date-mm-first date)) (to (mhc-date-mm-last date)) (today (mhc-date-now)) ;; need three months for mini-calendar (dayinfo-list (mhc-db-scan (mhc-date-mm-- from) (mhc-date-mm++ to)))) (unless (eq 'direct mailer) - (mhc-summary-generate-buffer date) + (mhc-summary-generate-buffer (or name date)) (setq mhc-summary-buffer-current-date-month (mhc-date-mm-first date))) (when mhc-use-wide-scope diff -Nru mhc-1.1.1+0.20171016/emacs/mhc-face.el mhc-1.1.1+0.20180314/emacs/mhc-face.el --- mhc-1.1.1+0.20171016/emacs/mhc-face.el 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/emacs/mhc-face.el 2018-03-14 07:04:13.000000000 +0000 @@ -68,7 +68,7 @@ (1 font-lock-type-face) (2 font-lock-comment-face) (3 font-lock-builtin-face)) - ("\\(X-SC-\\(Subject\\|Location\\|Day\\|Time\\|Category\\|Priority\\|Recurrence-Tag\\|Mission-Tag:\\|Cond\\|Duration\\|Alarm\\|Record-Id\\|Sequence\\):\\)" + ("\\(X-SC-\\(Subject\\|Location\\|Day\\|Time\\|Category\\|Priority\\|Recurrence-Tag\\|Mission-Tag\\|Cond\\|Duration\\|Alarm\\|Record-Id\\|Sequence\\):\\)" (1 font-lock-keyword-face)) ("\\(\\[End of message\\]\\)" (1 mhc-message-face-eof-marker)) diff -Nru mhc-1.1.1+0.20171016/emacs/mhc-process.el mhc-1.1.1+0.20180314/emacs/mhc-process.el --- mhc-1.1.1+0.20171016/emacs/mhc-process.el 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/emacs/mhc-process.el 2018-03-14 07:04:13.000000000 +0000 @@ -17,6 +17,21 @@ (accept-process-output mhc-process 0.5))) (read (buffer-substring (point-min) (1- (point-max)))))) +(defun mhc-process-send-command-with-buffer (command buffer) + "Send COMMAND to mhc process with BUFFER via temporal file." + (let ((temp-file (make-temp-file "mhc"))) + (unwind-protect + (with-current-buffer buffer + (mhc-write-region-as-coding-system + mhc-default-coding-system + (point-min) + (point-max) + temp-file + nil 'nomsg) + (mhc-process-send-command + (format "%s %s" command temp-file))) + (delete-file temp-file)))) + (defun mhc-start-process () (interactive) (let ((process-connection-type nil)) ;; use PIPE not tty diff -Nru mhc-1.1.1+0.20171016/emacs/mhc-schedule.el mhc-1.1.1+0.20180314/emacs/mhc-schedule.el --- mhc-1.1.1+0.20171016/emacs/mhc-schedule.el 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/emacs/mhc-schedule.el 2018-03-14 07:04:13.000000000 +0000 @@ -142,7 +142,10 @@ (defun mhc-schedule-subject-as-string (schedule) - (or (mhc-schedule-subject schedule) "(none)")) + (let ((subject (mhc-schedule-subject schedule))) + (if (eq (length subject) 0) + "(no subject)" + subject))) (defun mhc-schedule-categories-as-string (schedule) diff -Nru mhc-1.1.1+0.20171016/emacs/mhc-summary.el mhc-1.1.1+0.20180314/emacs/mhc-summary.el --- mhc-1.1.1+0.20171016/emacs/mhc-summary.el 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/emacs/mhc-summary.el 2018-03-14 07:04:13.000000000 +0000 @@ -171,6 +171,8 @@ 'face mhc-tmp-day-face) (?/ (if mhc-tmp-first "/" " ") 'face mhc-tmp-day-face) + (?- (if mhc-tmp-first "-" " ") + 'face mhc-tmp-day-face) (?S " " 'face mhc-tmp-day-face) (?M (mhc-summary/line-month-string) 'face mhc-tmp-day-face) @@ -182,7 +184,8 @@ (make-string 5 ? ) (format "%02d:%02d" (/ mhc-tmp-begin 60) (% mhc-tmp-begin 60))) 'face 'mhc-summary-face-time) - (?e (if (null mhc-tmp-end) + (?e (if (or (null mhc-tmp-end) + (and mhc-tmp-begin (= mhc-tmp-end mhc-tmp-begin))) (make-string 6 ? ) (format "-%02d:%02d" (/ mhc-tmp-end 60) (% mhc-tmp-end 60))) 'face 'mhc-summary-face-time) @@ -498,10 +501,10 @@ (defun mhc-summary/line-subject-string () - (if mhc-tmp-private - (and mhc-tmp-schedule mhc-summary-string-secret) - (or (mhc-schedule-subject mhc-tmp-schedule) ""))) - + (if mhc-tmp-schedule + (if mhc-tmp-private + mhc-summary-string-secret + (mhc-schedule-subject-as-string mhc-tmp-schedule)))) (defun mhc-summary/line-location-string () (let ((location (mhc-schedule-location mhc-tmp-schedule))) @@ -661,7 +664,7 @@ (defun mhc-summary-buffer-p (&optional buffer) (if buffer (set-buffer buffer)) - mhc-summary-buffer-current-date-month) + (eq major-mode 'mhc-summary-mode)) (defun mhc-summary-current-date (&optional p) (when (mhc-summary-buffer-p) diff -Nru mhc-1.1.1+0.20171016/lib/mhc/formatter/emacs.rb mhc-1.1.1+0.20180314/lib/mhc/formatter/emacs.rb --- mhc-1.1.1+0.20171016/lib/mhc/formatter/emacs.rb 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/lib/mhc/formatter/emacs.rb 2018-03-14 07:04:13.000000000 +0000 @@ -17,12 +17,15 @@ end def format_item(context, date, item) + subject = item.subject.to_s + subject = "(no subject)" if subject == "" + # [ RECORD CONDITION SUBJECT LOCATION (TIMEB . TIMEE) ALARM # CATEGORIES PRIORITY REGION RECURRENCE-TAG] format("[(%s . [%s nil nil]) nil %s %s (%s . %s) %s (%s) nil nil %s]", elisp_string(item.path.to_s), elisp_string(item.uid.to_s), - elisp_string(item.subject), + elisp_string(subject), elisp_string(item.location), (item.time_range.first ? (item.time_range.first.to_i / 60) : "nil"), (item.time_range.last ? (item.time_range.last.to_i / 60) : "nil"), diff -Nru mhc-1.1.1+0.20171016/lib/mhc/formatter/text.rb mhc-1.1.1+0.20180314/lib/mhc/formatter/text.rb --- mhc-1.1.1+0.20171016/lib/mhc/formatter/text.rb 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/lib/mhc/formatter/text.rb 2018-03-14 07:04:13.000000000 +0000 @@ -6,10 +6,12 @@ end def format_item(context, date, item) + subject = item.subject.to_s + subject = "(no subject)" if subject == "" format("%s%-11s %s%s\n", format_item_header(context, date, item), item.time_range.to_mhc_string.toutf8, - item.subject.to_s.toutf8, + subject.toutf8, append(enclose(item.location)).toutf8 ) end diff -Nru mhc-1.1.1+0.20171016/lib/mhc/occurrence.rb mhc-1.1.1+0.20180314/lib/mhc/occurrence.rb --- mhc-1.1.1+0.20171016/lib/mhc/occurrence.rb 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/lib/mhc/occurrence.rb 2018-03-14 07:04:13.000000000 +0000 @@ -98,7 +98,8 @@ return "#{dtstart.to_mhc_string}" if oneday? return "#{@start_date.to_mhc_string}-#{@end_date.to_mhc_string}" else - return dtstart.strftime("%Y%m%d %H:%m-") + ((@start_date == @end_date) ? dtend.strftime("%H:%m") : dtend.strftime("%Y%m%dT%H:%m")) + time = dtstart.strftime("%Y%m%d %H:%m-") + ((@start_date.to_date == @end_date.to_date) ? dtend.strftime("%H:%m") : dtend.strftime("%Y%m%dT%H:%m")) + return time + " " + subject.to_mhc_string end end diff -Nru mhc-1.1.1+0.20171016/lib/mhc/property_value/date.rb mhc-1.1.1+0.20180314/lib/mhc/property_value/date.rb --- mhc-1.1.1+0.20171016/lib/mhc/property_value/date.rb 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/lib/mhc/property_value/date.rb 2018-03-14 07:04:13.000000000 +0000 @@ -12,7 +12,7 @@ begin # YYYYMMDD/HH:MM => DateTime if /^(\d{4})(\d{2})(\d{2})\/(\d{2}):(\d{2})$/ =~ string - DateTime.new($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, 0, DateTime.now.zone) + DateTime.new($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, 0) # YYYYMMDD => Date elsif /^(\d{4})(\d{2})(\d{2})$/ =~ string @@ -20,7 +20,7 @@ # YYYYMMDD/hh:mm-HH:MM => DateTime taking YYYYMMDD, HH:MM elsif /^(\d+):(\d+)$/ =~ string && default - DateTime.new(default.year, default.month, default.day, $1.to_i, $2.to_i, 0, DateTime.now.zone) + DateTime.new(default.year, default.month, default.day, $1.to_i, $2.to_i, 0) else fail ParseError diff -Nru mhc-1.1.1+0.20171016/lib/mhc/property_value/period.rb mhc-1.1.1+0.20180314/lib/mhc/property_value/period.rb --- mhc-1.1.1+0.20171016/lib/mhc/property_value/period.rb 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/lib/mhc/property_value/period.rb 2018-03-14 07:04:13.000000000 +0000 @@ -4,7 +4,7 @@ UNIT2MIN = {'minute' => 1, 'hour' => 60, 'day' => 60*24} UNITS = UNIT2MIN.keys - REGEXP = /(\d+)\s*(#{UNITS.join("|")})s?/ + REGEXP = /(\d+)\s*(#{UNITS.join("|")})s?$/ def self.parse(string) return new.parse(string) @@ -13,6 +13,8 @@ def parse(string) if REGEXP =~ string @minutes = (UNIT2MIN[$2] * $1.to_i) + else + raise ParseError, "invalid period string \"#{string}\"" end return self end diff -Nru mhc-1.1.1+0.20171016/spec/mhc_spec.rb mhc-1.1.1+0.20180314/spec/mhc_spec.rb --- mhc-1.1.1+0.20171016/spec/mhc_spec.rb 2017-10-16 10:35:13.000000000 +0000 +++ mhc-1.1.1+0.20180314/spec/mhc_spec.rb 2018-03-14 07:04:13.000000000 +0000 @@ -125,6 +125,20 @@ end + it "should emit an error on parsing invalid time format." do + str = <<-EOF.strip_heredoc + X-SC-Subject: Invalid Date format + X-SC-Location: Room1 + X-SC-Day: 19960930 + X-SC-Duration: 19960930- + X-SC-Time: 19:30-2030 + X-SC-Record-Id: 54A339AD-F7FD-4E56-9B70-2D09F840E94D + X-SC-Sequence: 0 + EOF + errors = Mhc::Event.validate(str) + expect(errors.length).to eq 1 + expect(errors.first.first.message).to match /invalid time format/ + end it "should occur weekly on Monday and Thursday from 2014-04-01 to 2014-04-30 with exception of 2014-04-10 (Thu)" do ev = Mhc::Event.parse <<-EOF.strip_heredoc @@ -204,6 +218,53 @@ ["20140203 10:00-12:00 TEST", "20140509 10:00-12:00 TEST", "20140831 10:00-12:00 TEST"] end + it "should produce a list of occurrences, and one occurrence has different Time" do + ev = Mhc::Event.parse <<-EOF.strip_heredoc + X-SC-Subject: X-Project + X-SC-Location: 101 + X-SC-Day: 20160601 20160602/16:00-18:00 20160616 20160617 20160623 20160624 + X-SC-Time: 09:00-11:00 + X-SC-Category: Conference + X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3 + EOF + expect(ev.occurrences.take(30).map{|o| "#{o.dtstart.strftime("%Y%m%d/%H:%M")}-#{o.dtend.strftime("%Y%m%d/%H:%M")} #{o.subject}"}).to eq \ + ["20160601/09:00-20160601/11:00 X-Project", + "20160602/16:00-20160602/18:00 X-Project", + "20160616/09:00-20160616/11:00 X-Project", + "20160617/09:00-20160617/11:00 X-Project", + "20160623/09:00-20160623/11:00 X-Project", + "20160624/09:00-20160624/11:00 X-Project"] + end + + it "should produce a list of occurrences, and one occurrence has different Time crossing days" do + ev = Mhc::Event.parse <<-EOF.strip_heredoc + X-SC-Subject: TEST + X-SC-Time: 10:00-12:00 + X-SC-Day: 20150203/10:30-20150205/12:30 20150509 20150831 + X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3 + EOF + + expect(ev.occurrences.take(30).map{|o| "#{o.dtstart.strftime("%Y%m%d/%H:%M")}-#{o.dtend.strftime("%Y%m%d/%H:%M")} #{o.subject}"}).to eq \ + ["20150203/10:30-20150205/12:30 TEST", + "20150509/10:00-20150509/12:00 TEST", + "20150831/10:00-20150831/12:00 TEST"] + + expect(ev.to_ics).to eq <<-'EOF'.strip_heredoc + BEGIN:VEVENT + RDATE;VALUE=PERIOD:20150509T100000Z/20150509T120000Z,20150831T100000Z/20150831T120000Z + CREATED;VALUE=DATE-TIME:20140101T000000Z + DTEND;VALUE=DATE-TIME:20150205T123000Z + DTSTART;VALUE=DATE-TIME:20150203T103000Z + DTSTAMP;VALUE=DATE-TIME:20140101T000000Z + LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z + UID:FEDA4C97-21C2-46AA-A395-075856FBD5C3 + DESCRIPTION: + SUMMARY:TEST + SEQUENCE:0 + END:VEVENT + EOF + end + it "should return true when #allday? is called if X-SC-Time: is blank" do ev = Mhc::Event.parse <<-EOF.strip_heredoc X-SC-Subject: TEST @@ -383,6 +444,28 @@ X-SC-Record-Id: 69CFD0DF-4058-425B-8C2B-40D81E6A2392 EOF expect(ev.to_ics).to eq <<-'EOF'.strip_heredoc + BEGIN:VEVENT + CREATED;VALUE=DATE-TIME:20140101T000000Z + DTEND;VALUE=DATE-TIME:20140509T101000Z + DTSTART;VALUE=DATE-TIME:20140508T120000Z + DTSTAMP;VALUE=DATE-TIME:20140101T000000Z + LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z + UID:69CFD0DF-4058-425B-8C2B-40D81E6A2392 + DESCRIPTION: + SUMMARY:CS1 + SEQUENCE:0 + END:VEVENT + EOF + end + + it "should return icalendar VEVENT over 24h event" do + ev = Mhc::Event.parse <<-EOF.strip_heredoc + X-SC-Subject: CS1 + X-SC-Time: 12:00-13:00 + X-SC-Day: 20140508/12:00-20140509/10:10 + X-SC-Record-Id: 69CFD0DF-4058-425B-8C2B-40D81E6A2392 + EOF + expect(ev.to_ics).to eq <<-'EOF'.strip_heredoc BEGIN:VEVENT CREATED;VALUE=DATE-TIME:20140101T000000Z DTEND;VALUE=DATE-TIME:20140509T101000Z