#!/usr/bin/perl # use strict ; use Time::Local ; use Jcode ; use Net::Google::Calendar; use MIME::QuotedPrint ; use POSIX 'strftime' ; use Text::vFile::asData ; use DateTime::Duration ; use DateTime::Format::W3CDTF ; require "getopts.pl" ; Getopts( 'c:m:' ) ; # Google Calendar の登録情報 our $url = 'http://www.google.com/calendar/feeds/xxxx%40gmail.com/' .'private-xxxx/basic' ; our $user = 'xxxx@gmail.com'; our $pass = 'xxxx'; our $mailto = "yyyy" ; our $mailfrom = 'yyyy@example.co.jp' ; # 設定ファイルの読み込み require 'google-calendar.conf' unless( $opt_c ) ; require $opt_c if ( $opt_c && -f $opt_c ) ; $mailto = $opt_m if ( $opt_m ) ; # 一時的に生成するVCSファイル my $tempdir = "/tmp" ; my $file = "$tempdir/google-calendar-$$.vcs" ; # SUMMARY から CATEGORIES を生成する sub categories( $ ) { my $str = Jcode->new( shift , "utf8" )->euc ; if ( $str =~ /会議/ || $str =~ /委員会/ ) { return "MEETING" ; } elsif ( $str =~ /会$/ ) { return "MEETING" ; } elsif ( $str =~ /研修/ || $str =~ /仕事/ ) { return "BUSINESS" ; } elsif ( $str =~ /代休/ || $str =~ /休暇/ || $str =~ /休み/ || $str =~ /休日/ ) { return "HOLIDAY" ; } elsif ( $str =~ /出張/ || $str =~ /旅行/ ) { return "TRAVEL" ; } elsif ( $str =~ /電話/ || $str =~ /TEL/i ) { return "TELEPHONE" ; } elsif ( $str =~ /メール/ || $str =~ /Mail/i ) { return "MAIL" ; } elsif ( $str =~ /デート/ ) { return "DATE" ; } elsif ( $str =~ /食事/ ) { return "DINNER" ; } elsif ( $str =~ /宴会/ || $str =~ /パーティ/ || $str =~ /飲み会/ ) { return "PARTY" ; } elsif ( $str =~ /病院/ || $str =~ /診察/ || $str =~ /検診/ ) { return "HOSPITAL" ; } elsif ( $str =~ /誕生日/ ) { return "BIRTHDAY" ; } elsif ( $str =~ /記念日/ ) { return "MEMORIALDAY" ; } elsif ( $str =~ /〆切/ || $str =~ /締切/ || $str =~ /締め切り/ ) { return "DEADLINE" ; } else { return "MISCELLANEOUS" ; } } # QuotedPrintableに変換したデータを返す sub encode_qp_key( $$ ) { my $key = shift ; my $val = shift ; $val = Jcode->new( $val , "utf8" )->sjis ; my $dummy = " "x(length($key)) ; my $ans = encode_qp( $dummy.$val , "\n" ) ; $ans =~ s/^$dummy/$key/ ; return $ans ; } # 取得した日付をVCalendar用の日付に変更 sub vcal_event( $$ ) { my $key = shift ; my $date = shift ; $date =~ s/[-:]//g ; if ( $date =~ /^(\d\d\d\d)(\d\d)(\d\d)(|Z)$/ ) { # 終日イベント return "$key;VALUE=DATE:$date" ; } else { # UTC時間にする return "$key:$date"."Z" ; } } sub vcal_event_allday( $$ ) { my $key = shift ; my $date = shift ; $date =~ s/[-:]//g ; if ( $date =~ /^(\d\d\d\d)(\d\d)(\d\d)/ ) { # 終日イベント return "$key;VALUE=DATE:$date" ; } else { # UTC時間にする return "$key:$date"."Z" ; } } # Google Calendar に接続 my $cal = Net::Google::Calendar->new( url => $url ); # $cal->{_ua}->env_proxy; # (2) $cal->login($user, $pass) or die $@; # (3) # VCalendarファイルの生成 open( VCS , ">$file" ) || die( "Can't open for write $file" ) ; print VCS <<"EOF" ; BEGIN:VCALENDAR VERSION:1.0 PRODID:Google Calendar and vCal converter EOF # 過去のイベントを除外するための比較対象 my $now = time() ; my $dt_fmt = DateTime::Format::W3CDTF->new ; my $dt_start = DateTime->from_epoch( time_zone => 'Asia/Tokyo' , epoch => $now ) ; my $fm_start = $dt_fmt->format_datetime( $dt_start ) ; my $dt_end = DateTime->from_epoch( time_zone => 'Asia/Tokyo' , epoch => $now + 24*3600*180 ) ; my $fm_end = $dt_fmt->format_datetime( $dt_end ) ; my $cals = "" ; # すべてのカレンダーで繰り返し foreach my $cc ( $cal->get_calendars ) { # カレンダー名の取得 $cal->set_calendar( $cc ) ; $cals .= " ".$cc->title ; my $start_index = 1 ; my $max_results = 20 ; # 先頭から $max_results 件づつ読みだし while( 1 ) { # printf( "get_events(%d,%d)\n" , $start_index , $max_results ) ; my @ev = $cal->get_events( 'start-min' => $fm_start , 'start-max' => $fm_end , 'start-index' => $start_index , 'max-results' => $max_results ) ; # 読み出し件数0で抜ける last if ( @ev == 0 ) ; # 読み出した1件づつのイベントの処理 foreach my $ee ( @ev ) { # $ee->recurrenceのコードにテストprintが残ってるので my $re = $ee->get( $ee->{_gd_ns} , 'recurrence' ) ; # 繰り返しイベントの処理は難しいので無視 unless( $re ) { my @when = $ee->when ; print VCS "BEGIN:VEVENT\n" ; # イベントの名前 #print "#".Jcode->new( $ee->title )->euc."\n" ; print VCS encode_qp_key( "SUMMARY;ENCODING=QUOTED-PRINTABLE:" , $ee->title )."\n" ; # イベントの詳細 print VCS encode_qp_key( "DESCRIPTION;ENCODING=QUOTED-PRINTABLE:" , $ee->content->body )."\n" if ( $ee->content->body ) ; # イベントの場所 print VCS encode_qp_key( "LOCATION;ENCODING=QUOTED-PRINTABLE:" , $ee->location )."\n" if ( $ee->location ) ; # イベントのカテゴリ print VCS "CATEGORIES:".categories( $ee->title )."\n" ; # 開始終了時間 if ( $when[0] =~ /^(\d\d\d\d)-(\d\d)-(\d\d)T00:00:00(|Z)$/ && $when[1] =~ /^(\d\d\d\d)-(\d\d)-(\d\d)T00:00:00(|Z)$/ ) { print VCS vcal_event_allday( "DTSTART" , $when[0] )."\n" ; print VCS vcal_event_allday( "DTEND" , $when[1] )."\n" ; } else { print VCS vcal_event( "DTSTART" , $when[0] )."\n" ; print VCS vcal_event( "DTEND" , $when[1] )."\n" ; } print VCS "END:VEVENT\n" ; } } # 読みだし位置の移動 $start_index += @ev ; } } print VCS "END:VCALENDAR\n" ; close( VCS ) ; # 完成したファイルをメールの添付ファイルで送信 if ( -f $file && $mailto ne "" ) { # 変換&送信用のプログラム my $base64_prog = "/usr/bin/base64" ; my $sendmail_prog = "/usr/sbin/qmail-inject" ; # Base64に変換して読み込む open( VCSB64 , "$base64_prog $file |" ) || die( "Can't open program $base64_prog" ) ; # Sendmailに送り出す open( MAIL , "| $sendmail_prog" ) || die( "Can't open program $sendmail_prog" ) ; # 添付ファイルの境界文字列 my $boundary = "=/=/=ical.pl_".time."_".$$ ; # メールヘッダ print MAIL "From: $mailfrom\n" ; print MAIL "To: $mailto\n" ; print MAIL "Subject: [VCS] Google Calendar\n" ; print MAIL "Mime-Version: 1.0\n" ; print MAIL "Content-Type: multipart/mixed; boundary=\"$boundary\"\n" ; print MAIL "\n" ; # 本文 print MAIL "--$boundary\n" ; print MAIL "Content-Type: text/plain; charset=\"iso-2022-jp\"\n" ; print MAIL "Content-Transfer-Encoding: 7bit\n\n" ; print MAIL Jcode->new( "[添付]" )->jis."\n--\n" .Jcode->new( "Calendar:$cals" )->jis."\n" .Jcode->new( strftime( "%Y/%m/%d" , localtime )." 現在" )->jis."\n\n" ; # 添付ヘッダ print MAIL "--$boundary\n" ; print MAIL "Content-Type: text/x-vcalendar; charset=Shift_JIS; name=\"Google.VCS\"\n" ; print MAIL "Content-Transfer-Encoding: base64\n" ; print MAIL "Content-Disposition: attachment; filename=\"Google.VCS\"\n\n" ; # 添付本体 while( ) { print MAIL $_ ; } print MAIL "\n--$boundary--\n" ; close( MAIL ) ; close( VCSB64 ) ; unlink( $file ) ; }