Changeset 504
- Timestamp:
- 08/28/08 02:04:02 (3 months ago)
- Location:
- cybozu2ical/trunk
- Files:
-
- 3 modified
-
cybozu2ical (modified) (8 diffs)
-
lib/WWW/CybozuOffice6/Calendar.pm (modified) (12 diffs)
-
lib/WWW/CybozuOffice7/Calendar.pm (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
cybozu2ical/trunk/cybozu2ical
r502 r504 22 22 ### 23 23 *Data::ICal::Property::_value_as_string = sub { 24 my $self = shift;25 my $key = shift;26 my $value = defined( $self->value()) ? $self->value() : '';27 28 unless ( $self->vcal10) {24 my $self = shift; 25 my $key = shift; 26 my $value = defined( $self->value() ) ? $self->value() : ''; 27 28 unless ( $self->vcal10 ) { 29 29 my $lc_key = lc($key); 30 30 $value =~ s/\\/\\/gs; 31 $value =~ s/\Q;/\\;/gs unless ($lc_key eq 'rrule' || $lc_key eq 'exdate'); 32 $value =~ s/,/\\,/gs unless ($lc_key eq 'rrule' || $lc_key eq 'exdate'); 31 $value =~ s/\Q;/\\;/gs 32 unless ( $lc_key eq 'rrule' || $lc_key eq 'exdate' ); 33 $value =~ s/,/\\,/gs 34 unless ( $lc_key eq 'rrule' || $lc_key eq 'exdate' ); 33 35 $value =~ s/\n/\\n/gs; 34 36 $value =~ s/\\N/\\N/gs; … … 43 45 ### 44 46 sub to_icaldate { 45 my($dt, $is_full_day) = @_; 46 $is_full_day ? 47 $dt->ymd('') : 48 $dt->ymd('') . 'T' . $dt->hms('') . ($dt->time_zone->is_utc ? 'Z' : ''); 47 my ( $dt, $is_full_day ) = @_; 48 $is_full_day 49 ? $dt->ymd('') 50 : $dt->ymd('') . 'T' 51 . $dt->hms('') 52 . ( $dt->time_zone->is_utc ? 'Z' : '' ); 49 53 } 50 54 51 55 sub encode_string { 52 my($enc, $text) = @_; 53 if ($enc eq 'ncr') { 54 $text =~ s/(\P{ASCII})/sprintf("&#%d;", ord($1))/eg; 55 } else { 56 $text = encode($enc, $text); 56 my ( $enc, $text ) = @_; 57 if ( $enc eq 'ncr' ) { 58 $text =~ s/(\P{ASCII})/sprintf("&#%d;", ord($1))/eg; 59 } 60 else { 61 $text = encode( $enc, $text ); 57 62 } 58 63 $text; … … 62 67 my $file = shift; 63 68 my $yaml; 64 if (eval('require YAML::Tiny')) { 65 ($yaml) = YAML::Tiny::LoadFile($file); 66 } elsif (eval('require YAML')) { 67 ($yaml) = YAML::LoadFile($file); 69 if ( eval('require YAML::Tiny') ) { 70 ($yaml) = YAML::Tiny::LoadFile($file); 71 } 72 elsif ( eval('require YAML') ) { 73 ($yaml) = YAML::LoadFile($file); 68 74 } 69 75 if ($@) { 70 die "Faild to read yaml file: $@";76 die "Faild to read yaml file: $@"; 71 77 } 72 78 $yaml; … … 79 85 # Handle command-line options 80 86 my %opt = ( 81 conf => 'config.yaml',82 'compat-google-calendar' => 0,87 conf => 'config.yaml', 88 'compat-google-calendar' => 0, 83 89 ); 84 GetOptions(\%opt, 85 'output=s', 86 'conf=s', 87 'compat-google-calendar', 88 'debug', 89 'input-csv=s', 90 'output-csv=s', 91 'help', 92 ) or pod2usage(2); 90 GetOptions( \%opt, 'output=s', 'conf=s', 'compat-google-calendar', 'debug', 91 'input-csv=s', 'output-csv=s', 'help', ) 92 or pod2usage(2); 93 93 pod2usage(1) if $opt{help}; 94 94 95 95 # Read configuration file 96 my $cfg = read_yaml( $opt{conf});96 my $cfg = read_yaml( $opt{conf} ); 97 97 my $time_zone = $cfg->{time_zone} || 'Asia/Tokyo'; 98 98 … … 103 103 calscale => 'GREGORIAN', 104 104 method => 'PUBLISH', 105 $cfg->{calname} ? ( 'X-WR-CALNAME' => $cfg->{calname}) : (),105 $cfg->{calname} ? ( 'X-WR-CALNAME' => $cfg->{calname} ) : (), 106 106 'X-WR-TIMEZONE' => $time_zone 107 107 ); 108 108 109 109 # Obtain Cybozu Office 6/7 Calendar items 110 my $cal_class = $cfg->{cybozu_version} == 7 ? 111 'WWW::CybozuOffice7::Calendar' : 'WWW::CybozuOffice6::Calendar'; 110 my $cal_class = 111 $cfg->{cybozu_version} == 7 112 ? 'WWW::CybozuOffice7::Calendar' 113 : 'WWW::CybozuOffice6::Calendar'; 112 114 eval "use $cal_class;"; 113 115 my $cal = $cal_class->new(%$cfg); 114 116 115 if ($opt{'input-csv'}) { 116 $cal->read_from_csv_file($opt{'input-csv'}) 117 or die "Failed to read CSV file: $opt{'input-csv'}"; 118 } else { 117 if ( $opt{'input-csv'} ) { 118 $cal->read_from_csv_file( $opt{'input-csv'} ) 119 or die "Failed to read CSV file: $opt{'input-csv'}"; 120 } 121 else { 119 122 $cal->request() 120 or die "Failed to get Cybozu Office 6 Calendar";123 or die "Failed to get Cybozu Office 6 Calendar"; 121 124 } 122 125 123 126 # Output the calendar CSV for debugging 124 if ( $opt{'output-csv'}) {127 if ( $opt{'output-csv'} ) { 125 128 local *FH; 126 129 open FH, ">$opt{'output-csv'}" or die "Failed to write $opt{'output-csv'}"; … … 130 133 131 134 # For each items, generate an 'event entry' and append it to the calendar 132 for my $item ( $cal->get_items()) {135 for my $item ( $cal->get_items() ) { 133 136 my $vevent = Data::ICal::Entry::Event->new(); 134 my %args = (135 summary => decode_utf8($item->summary),136 description => decode_utf8($item->description),137 created => to_icaldate($item->created),138 dtstamp => to_icaldate($item->modified),139 url => $cal->url . '?page=ScheduleView&EID=' . $item->id,137 my %args = ( 138 summary => decode_utf8( $item->summary ), 139 description => decode_utf8( $item->description ), 140 created => to_icaldate( $item->created ), 141 dtstamp => to_icaldate( $item->modified ), 142 url => $cal->url . '?page=ScheduleView&EID=' . $item->id, 140 143 ); 141 144 142 $args{comment} = decode_utf8($item->comment) 143 if $opt{debug} && $item->comment; 144 145 if ($item->is_full_day) { 146 $args{dtstart} = [ to_icaldate($item->start, 1), { VALUE => 'DATE' } ]; 147 $args{dtend} = [ to_icaldate($item->end, 1), { VALUE => 'DATE' } ]; 148 } else { 149 $args{dtstart} = [ to_icaldate($item->start, 0), { TZID => $time_zone } ]; 150 $args{dtend} = [ to_icaldate($item->end, 0), { TZID => $time_zone } ]; 145 $args{comment} = decode_utf8( $item->comment ) 146 if $opt{debug} && $item->comment; 147 148 if ( $item->is_full_day ) { 149 $args{dtstart} = 150 [ to_icaldate( $item->start, 1 ), { VALUE => 'DATE' } ]; 151 $args{dtend} = [ to_icaldate( $item->end, 1 ), { VALUE => 'DATE' } ]; 152 } 153 else { 154 $args{dtstart} = 155 [ to_icaldate( $item->start, 0 ), { TZID => $time_zone } ]; 156 $args{dtend} = [ to_icaldate( $item->end, 0 ), { TZID => $time_zone } ]; 151 157 } 152 158 153 159 # handle frequency 154 if ($item->can('rrule')) { 155 # rrule 156 my %rrule = %{$item->rrule}; 157 $rrule{UNTIL} = to_icaldate($rrule{UNTIL}, $item->is_full_day) 158 if $rrule{UNTIL}; 159 $rrule{WKST} = 'SU' 160 if $opt{'compat-google-calendar'}; 161 162 my @rrule_list; 163 for (qw(FREQ COUNT INTERVAL BYMONTH BYMONTHDAY WKST BYDAY UNTIL)) { 164 push @rrule_list, $_ . '=' . $rrule{$_} 165 if exists $rrule{$_}; 166 } 167 $args{rrule} = join ';', @rrule_list; 168 169 # exdate 170 if ($item->exdates) { 171 if ($item->is_full_day) { 172 my $exdate = join ',', map { to_icaldate($_, 1) } $item->exdates; 173 $args{exdate} = [ $exdate, { VALUE => 'DATE' } ]; 174 } else { 175 my $exdate = join ',', map { to_icaldate($_, 0) } $item->exdates; 176 $args{exdate} = [ $exdate, { TZID => $time_zone } ]; 177 } 178 } 160 if ( $item->can('rrule') ) { 161 162 # rrule 163 my %rrule = %{ $item->rrule }; 164 $rrule{UNTIL} = to_icaldate( $rrule{UNTIL}, $item->is_full_day ) 165 if $rrule{UNTIL}; 166 $rrule{WKST} = 'SU' 167 if $opt{'compat-google-calendar'}; 168 169 my @rrule_list; 170 for (qw(FREQ COUNT INTERVAL BYMONTH BYMONTHDAY WKST BYDAY UNTIL)) { 171 push @rrule_list, $_ . '=' . $rrule{$_} 172 if exists $rrule{$_}; 173 } 174 $args{rrule} = join ';', @rrule_list; 175 176 # exdate 177 if ( $item->exdates ) { 178 if ( $item->is_full_day ) { 179 my $exdate = join ',', 180 map { to_icaldate( $_, 1 ) } $item->exdates; 181 $args{exdate} = [ $exdate, { VALUE => 'DATE' } ]; 182 } 183 else { 184 my $exdate = join ',', 185 map { to_icaldate( $_, 0 ) } $item->exdates; 186 $args{exdate} = [ $exdate, { TZID => $time_zone } ]; 187 } 188 } 179 189 180 190 } … … 189 199 # Generate a 'timezone entry' and append it to the calendar 190 200 my $vtimezone = Data::ICal::Entry::TimeZone->new(); 191 $vtimezone->add_properties( tzid => $time_zone);201 $vtimezone->add_properties( tzid => $time_zone ); 192 202 193 203 # probably we need to support the Daylight Saving Time, but not yet supported. 194 204 my $standard = Data::ICal::Entry::TimeZone::Standard->new(); 195 my $std = DateTime->new(year => 1970, month => 1, day => 1, 196 hour => 0, minute => 0, second => 0, 197 time_zone => $time_zone); 198 my $offset = DateTime::TimeZone::offset_as_string($std->offset) || '+0900'; 205 my $std = DateTime->new( 206 year => 1970, 207 month => 1, 208 day => 1, 209 hour => 0, 210 minute => 0, 211 second => 0, 212 time_zone => $time_zone 213 ); 214 my $offset = DateTime::TimeZone::offset_as_string( $std->offset ) || '+0900'; 199 215 my $tzname = $cfg->{tzname} || 'JST'; 200 216 … … 210 226 211 227 # Outputs the calendar as a string 212 my $text = encode_string($cfg->{output_encoding} || 'utf8', $vcalendar->as_string); 213 if ($opt{output}) { 228 my $text = 229 encode_string( $cfg->{output_encoding} || 'utf8', $vcalendar->as_string ); 230 if ( $opt{output} ) { 214 231 local *FH; 215 232 open FH, ">$opt{output}" or die "Failed to write $opt{output}"; 216 233 print FH $text; 217 234 close FH; 218 } else { 235 } 236 else { 219 237 print $text; 220 238 } -
cybozu2ical/trunk/lib/WWW/CybozuOffice6/Calendar.pm
r503 r504 14 14 15 15 sub new { 16 my ($class, %param) = @_;17 $param{url} ||= delete $param{cybozu_url};18 $param{host} ||= URI->new( $param{url})->host;19 $param{ua} ||= LWP::UserAgent->new();16 my ( $class, %param ) = @_; 17 $param{url} ||= delete $param{cybozu_url}; 18 $param{host} ||= URI->new( $param{url} )->host; 19 $param{ua} ||= LWP::UserAgent->new(); 20 20 bless \%param, $class; 21 21 } 22 22 23 sub url { shift->_accessor('url', @_) } 24 sub host { shift->_accessor('host', @_) } 25 sub username { shift->_accessor('username', @_) } 26 sub userid { shift->_accessor('userid', @_) } 27 sub password { shift->_accessor('password', @_) } 28 sub ua { shift->_accessor('ua', @_) } 29 sub input_encoding { shift->_accessor('input_encoding', @_) } 23 sub url { shift->_accessor( 'url', @_ ) } 24 sub host { shift->_accessor( 'host', @_ ) } 25 sub username { shift->_accessor( 'username', @_ ) } 26 sub userid { shift->_accessor( 'userid', @_ ) } 27 sub password { shift->_accessor( 'password', @_ ) } 28 sub ua { shift->_accessor( 'ua', @_ ) } 29 sub input_encoding { shift->_accessor( 'input_encoding', @_ ) } 30 30 31 sub _accessor { 31 32 my $this = shift; 32 my $key = shift;33 my $key = shift; 33 34 $this->{$key} = shift if @_; 34 35 $this->{$key}; … … 38 39 my $this = shift; 39 40 40 my $res = $this->{ua}->post($this->{url} . '?page=SyncCalendar', { 41 _System => 'login', 42 _Login => 1, 43 csv => 1, 44 notimecard => 1, 45 defined $this->{username} ? (_Account => $this->{username}) : (), 46 defined $this->{userid} ? (_Id => $this->{userid} ) : (), 47 Password => $this->{password} || '', 48 }); 41 my $res = $this->{ua}->post( 42 $this->{url} . '?page=SyncCalendar', 43 { 44 _System => 'login', 45 _Login => 1, 46 csv => 1, 47 notimecard => 1, 48 defined $this->{username} ? ( _Account => $this->{username} ) : (), 49 defined $this->{userid} ? ( _Id => $this->{userid} ) : (), 50 Password => $this->{password} || '', 51 } 52 ); 49 53 confess 'Failed to access Cybozu Office 6: ' . $res->status_line 50 unless $res->is_success;54 unless $res->is_success; 51 55 52 56 my $content = $res->content; 53 from_to( $content, $this->{input_encoding} || 'shiftjis', 'utf8');54 my @lines = grep /^\d+,ts\.\d+,/, split( /\r?\n/, $content);57 from_to( $content, $this->{input_encoding} || 'shiftjis', 'utf8' ); 58 my @lines = grep /^\d+,ts\.\d+,/, split( /\r?\n/, $content ); 55 59 $this->{response} = \@lines; 56 60 … … 65 69 my @lines; 66 70 while (<FH>) { 67 chomp; push @lines, $_; 71 chomp; 72 push @lines, $_; 68 73 } 69 74 close(FH); … … 82 87 83 88 my $csv; 84 if (eval('require Text::CSV_XS')) { 85 $csv = Text::CSV_XS->new({ binary => 1 }); 86 } elsif (eval('require Text::CSV')) { 87 $csv = Text::CSV->new(); 88 } else { 89 confess 'Text::CSV_XS or Text::CSV package is required'; 89 if ( eval('require Text::CSV_XS') ) { 90 $csv = Text::CSV_XS->new( { binary => 1 } ); 91 } 92 elsif ( eval('require Text::CSV') ) { 93 $csv = Text::CSV->new(); 94 } 95 else { 96 confess 'Text::CSV_XS or Text::CSV package is required'; 90 97 } 91 98 92 99 my @items; 93 for my $line ($this->response) { 94 $csv->parse($line) 95 or confess 'Failed to parse CSV input'; 96 my @fields = $csv->fields; 97 my $num_fields = @fields - 1; 98 next if $num_fields < 13; 99 $fields[1] =~ s/^ts\.//; # remove rubbish 100 101 # Cybozu Calendar CSV Format 102 # GENERIC | RECCURENT 103 # [ 0] id? | id? 104 # [ 1] created | created 105 # [ 2] <BLANK> x start_date / end_date 106 # [ 3] start_date x initial start_date? 107 # [ 4] end_date x until_date 108 # [ 5] start_time | start_time 109 # [ 6] end_time | end_time 110 # [ 7] <BLANK> | freq 111 # [ 8] <BLANK> | freq_value 112 # [ 9] ??? | ??? 113 # [10] ??? | ??? 114 # [11] abbrev | abbrev 115 # [12] summary | summary 116 # [13] description | description 117 118 my %param; 119 @param{qw(id created start_time end_time freq freq_value abbrev summary description)} = @fields[0,1,5..8,11..13]; 120 $param{time_zone} = $this->{time_zone} || 'Asia/Tokyo'; 121 122 my $item; 123 if (!$param{freq}) { 124 @param{qw(start_date end_date)} = @fields[3,4]; 125 $item = WWW::CybozuOffice6::Calendar::Event->new(%param); 126 } else { 127 @param{qw(start_date end_date until_date)} = @fields[2,2,4]; 128 if ($num_fields > 13) { 129 my @exdates = @fields[14..$num_fields]; 130 $param{exdates} = \@exdates; 131 } 132 my $freq = $param{freq}; 133 if ($freq =~ /^[1-5]$/) { 134 $param{freq} = 'm'; 135 my @week_str = ('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'); 136 $param{freq_value} = $freq . $week_str[$param{freq_value}]; 137 } 138 $item = WWW::CybozuOffice6::Calendar::RecurrentEvent->new(%param); 139 } 140 141 next unless $item; 142 $item->comment($line); # save the CSV line as for debug info. 143 push @items, $item; 100 for my $line ( $this->response ) { 101 $csv->parse($line) 102 or confess 'Failed to parse CSV input'; 103 my @fields = $csv->fields; 104 my $num_fields = @fields - 1; 105 next if $num_fields < 13; 106 $fields[1] =~ s/^ts\.//; # remove rubbish 107 108 # Cybozu Calendar CSV Format 109 # GENERIC | RECCURENT 110 # [ 0] id? | id? 111 # [ 1] created | created 112 # [ 2] <BLANK> x start_date / end_date 113 # [ 3] start_date x initial start_date? 114 # [ 4] end_date x until_date 115 # [ 5] start_time | start_time 116 # [ 6] end_time | end_time 117 # [ 7] <BLANK> | freq 118 # [ 8] <BLANK> | freq_value 119 # [ 9] ??? | ??? 120 # [10] ??? | ??? 121 # [11] abbrev | abbrev 122 # [12] summary | summary 123 # [13] description | description 124 125 my %param; 126 @param{ 127 qw(id created start_time end_time freq freq_value abbrev summary description) 128 } = @fields[ 0, 1, 5 .. 8, 11 .. 13 ]; 129 $param{time_zone} = $this->{time_zone} || 'Asia/Tokyo'; 130 131 my $item; 132 if ( !$param{freq} ) { 133 @param{qw(start_date end_date)} = @fields[ 3, 4 ]; 134 $item = WWW::CybozuOffice6::Calendar::Event->new(%param); 135 } 136 else { 137 @param{qw(start_date end_date until_date)} = @fields[ 2, 2, 4 ]; 138 if ( $num_fields > 13 ) { 139 my @exdates = @fields[ 14 .. $num_fields ]; 140 $param{exdates} = \@exdates; 141 } 142 my $freq = $param{freq}; 143 if ( $freq =~ /^[1-5]$/ ) { 144 $param{freq} = 'm'; 145 my @week_str = ( 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA' ); 146 $param{freq_value} = $freq . $week_str[ $param{freq_value} ]; 147 } 148 $item = WWW::CybozuOffice6::Calendar::RecurrentEvent->new(%param); 149 } 150 151 next unless $item; 152 $item->comment($line); # save the CSV line as for debug info. 153 push @items, $item; 144 154 } 145 155 wantarray ? @items : $items[0]; … … 150 160 sub new { 151 161 my $class = shift; 152 my $self = {153 is_full_day => 0,154 modified=> DateTime->now,162 my $self = { 163 is_full_day => 0, 164 modified => DateTime->now, 155 165 }; 156 166 bless $self, $class; … … 159 169 } 160 170 161 sub id { shift->_accessor('id', @_) } 162 sub start { shift->_accessor('start', @_) } 163 sub end { shift->_accessor('end', @_) } 164 sub summary { shift->_accessor('summary', @_) } 165 sub description { shift->_accessor('description', @_) } 166 sub created { shift->_accessor('created', @_) } 167 sub modified { shift->_accessor('modified', @_) } 168 sub is_full_day { shift->_accessor('is_full_day', @_) } 169 sub comment { shift->_accessor('comment', @_) } 171 sub id { shift->_accessor( 'id', @_ ) } 172 sub start { shift->_accessor( 'start', @_ ) } 173 sub end { shift->_accessor( 'end', @_ ) } 174 sub summary { shift->_accessor( 'summary', @_ ) } 175 sub description { shift->_accessor( 'description', @_ ) } 176 sub created { shift->_accessor( 'created', @_ ) } 177 sub modified { shift->_accessor( 'modified', @_ ) } 178 sub is_full_day { shift->_accessor( 'is_full_day', @_ ) } 179 sub comment { shift->_accessor( 'comment', @_ ) } 180 170 181 sub _accessor { 171 182 my $this = shift; 172 my $key = shift;183 my $key = shift; 173 184 $this->{$key} = shift if @_; 174 185 $this->{$key}; … … 176 187 177 188 sub parse { 178 my ($this, %param) = @_;179 180 $this->{id} = $param{id}|| '0';189 my ( $this, %param ) = @_; 190 191 $this->{id} = $param{id} || '0'; 181 192 $this->{time_zone} = $param{time_zone} || 'Asia/Tokyo'; 182 193 183 my $start = $this->to_datetime( $param{start_date}, $param{start_time});184 my $end = $this->to_datetime( $param{end_date}, $param{end_time});194 my $start = $this->to_datetime( $param{start_date}, $param{start_time} ); 195 my $end = $this->to_datetime( $param{end_date}, $param{end_time} ); 185 196 return unless $start && $end; 186 197 187 198 # (start_time == empty) => A full-day event 188 199 # (start_time != empty) && (end_time == empty) => A malformed event 189 if ($param{start_time} eq ':') { 190 $start = $start->truncate(to => 'day'); 191 $end = $end->add(days => 1)->truncate(to => 'day'); 192 $this->{is_full_day} = 1; 193 } elsif ($param{end_time} eq ':') { 194 $end = $start->clone->add(minutes => 10); 200 if ( $param{start_time} eq ':' ) { 201 $start = $start->truncate( to => 'day' ); 202 $end = $end->add( days => 1 )->truncate( to => 'day' ); 203 $this->{is_full_day} = 1; 204 } 205 elsif ( $param{end_time} eq ':' ) { 206 $end = $start->clone->add( minutes => 10 ); 195 207 } 196 208 $this->{start} = $start; 197 209 $this->{end} = $end; 198 210 199 $this->{created} = DateTime->from_epoch(epoch => $param{created} || 0); 200 201 my $summary = ($param{abbrev} ? $param{abbrev} . ': ' : '') . $param{summary}; 211 $this->{created} = DateTime->from_epoch( epoch => $param{created} || 0 ); 212 213 my $summary = 214 ( $param{abbrev} ? $param{abbrev} . ': ' : '' ) . $param{summary}; 202 215 $this->{summary} = $summary; 203 216 $this->{description} = $param{description} || $summary; … … 208 221 sub to_datetime { 209 222 my $this = shift; 210 my ($ymd, $hms) = @_;223 my ( $ymd, $hms ) = @_; 211 224 212 225 my %args; 213 return unless $ymd && ($ymd =~ m!^(\d+)/(\d+)/(\d+)$! || $ymd =~ m!^da\.(\d+)\.(\d+)\.(\d+)$!); 214 @args{qw(year month day)} = ($1, $2, $3); 215 216 if ($hms && $hms ne ':') { 217 return unless $hms =~ m!^(\d+):(\d+)(?:\:?(\d+)?)$!; 218 @args{qw(hour minute second)} = ($1, $2, $3 || 0); 219 @args{qw(hour minute second)} = (23, 59, 59) if $args{hour} > 23; 220 } else { 221 @args{qw(hour minute second)} = (0, 0, 0); 226 return 227 unless $ymd 228 && ( $ymd =~ m!^(\d+)/(\d+)/(\d+)$! 229 || $ymd =~ m!^da\.(\d+)\.(\d+)\.(\d+)$! ); 230 @args{qw(year month day)} = ( $1, $2, $3 ); 231 232 if ( $hms && $hms ne ':' ) { 233 return unless $hms =~ m!^(\d+):(\d+)(?:\:?(\d+)?)$!; 234 @args{qw(hour minute second)} = ( $1, $2, $3 || 0 ); 235 @args{qw(hour minute second)} = ( 23, 59, 59 ) if $args{hour} > 23; 236 } 237 else { 238 @args{qw(hour minute second)} = ( 0, 0, 0 ); 222 239 } 223 240 … … 231 248 use base qw( WWW::CybozuOffice6::Calendar::Event ); 232 249 233 sub rrule { shift->_accessor('rrule', @_) } 250 sub rrule { shift->_accessor( 'rrule', @_ ) } 251 234 252 # for compatibility 235 sub frequency { shift->_accessor('frequency', @_) }236 sub frequency_value { shift->_accessor('frequency_value', @_) }237 sub until { shift->_accessor('until', @_) }253 sub frequency { shift->_accessor( 'frequency', @_ ) } 254 sub frequency_value { shift->_accessor( 'frequency_value', @_ ) } 255 sub until { shift->_accessor( 'until', @_ ) } 238 256 239 257 sub exdates { … … 244 262 } 245 263 246 our %FREQUENCY = ( y => 'YEARLY', m => 'MONTHLY', w => 'WEEKLY', 247 d => 'DAILY', n => 'WEEKDAYS' ); 264 our %FREQUENCY = ( 265 y => 'YEARLY', 266 m => 'MONTHLY', 267 w => 'WEEKLY', 268 d => 'DAILY', 269 n => 'WEEKDAYS' 270 ); 271 248 272 sub parse { 249 my ($this, %param) = @_;273 my ( $this, %param ) = @_; 250 274 $this->SUPER::parse(%param); 251 275 … … 256 280 # rrule 257 281 my %rrule = (); 258 if ($FREQUENCY{$freq} eq 'WEEKDAYS') { 259 %rrule = ( FREQ => 'WEEKLY', BYDAY => 'MO,TU,WE,TH,FR' ); 260 } else { 261 %rrule = ( FREQ => $FREQUENCY{$freq} ); 262 } 263 if ($param{freq_value} =~ /^\d(SU|MO|TU|WE|TH|FR|SA)$/) { 264 $rrule{BYDAY} = $param{freq_value}; 265 $rrule{INTERVAL} = 1; 282 if ( $FREQUENCY{$freq} eq 'WEEKDAYS' ) {
![(please configure the [header_logo] section in trac.ini)](/public/chrome/common/trac_banner.png)