--- /home/alex/acatysmoof.com/openwebmail-current/tarfiles/openwebmail-1.90/cgi-bin/openwebmail/openwebmail-cal.pl	Fri Feb  7 23:51:53 2003
+++ /home/alex/acatysmoof.com/openwebmail-current/openwebmail-cal.pl	Thu Feb 13 03:21:07 2003
@@ -744,68 +744,98 @@
 
 ########################## DAYVIEW ###########################
 sub dayview {
-   my ($year, $month, $day)=@_;
-   my $g2l=time()+timeoffset2seconds($prefs{'timeoffset'}); # trick makes gmtime($g2l) return localtime in timezone of timeoffsset
+   my ($year, $month, $day) = @_;
+
+   my $g2l = time()+timeoffset2seconds($prefs{'timeoffset'}); # trick makes gmtime($g2l) return localtime in timezone of timeoffset
    my ($current_year, $current_month, $current_day)=(gmtime($g2l))[5,4,3];
-   $current_year+=1900; $current_month++;
+   $current_year+=1900;
+   $current_month++;
 
-   $year = $current_year if (!$year);
+   $year  = $current_year if (!$year);
    $month = $current_month if (!$month);
-   $day = $current_day if (!$day);
-   $year=2037 if ($year>2037);
-   $year=1970 if ($year<1970);
+   $day   = $current_day if (!$day);
+
+   $year  = 2037 if ($year>2037);
+   $year  = 1970 if ($year<1970);
+
 
    printheader();
 
    my $html = '';
+   $html = readtemplate("dayview.template");
+   $html = applystyle($html);
+
+
    my $temphtml;
+   $temphtml = startform(-name     => "yearform",
+			 -action   => "$config{'ow_cgiurl'}/openwebmail-cal.pl") .
+
+                  hidden(-name     => 'action',
+                         -default  => 'calday',
+                         -override => '1').
+
+                  hidden(-name     => 'month',
+                         -default  => $month,
+                         -override => '1').
+ 
+                  hidden(-name     => 'day',
+                         -default  => $day,
+                         -override => '1').
+ 
+                  hidden(-name     => 'sessionid',
+                         -default  => $thissession,
+                         -override => '1').
+ 
+                  hidden(-name     => 'folder',
+                         -default  => $folder,
+                         -override => '1').
+ 
+                  hidden(-name     => 'message_id',
+                         -default  => $messageid,
+                         -override => '1');
 
-   $html=readtemplate("dayview.template");
-   $html = applystyle($html);
 
-   $temphtml = startform(-name=>"yearform",
-			 -action=>"$config{'ow_cgiurl'}/openwebmail-cal.pl") .
-               hidden(-name=>'action',
-                      -default=>'calday',
-                      -override=>'1').
-               hidden(-name=>'month',
-                      -default=>$month,
-                      -override=>'1').
-               hidden(-name=>'day',
-                      -default=>$day,
-                      -override=>'1').
-               hidden(-name=>'sessionid',
-                      -default=>$thissession,
-                      -override=>'1').
-               hidden(-name=>'folder',
-                      -default=>$folder,
-                      -override=>'1').
-               hidden(-name=>'message_id',
-                      -default=>$messageid,
-                      -override=>'1');
    $html =~ s/\@\@\@STARTFORM\@\@\@/$temphtml/g;
 
-   $temphtml = textfield(-name=>'year',
-                         -default=>$year,
-                         -size=>'4',
-                         -accesskey=>'G',
-                         -override=>'1');
+   $temphtml = textfield(-name      => 'year',
+                         -default   => $year,
+                         -size      => '4',
+                         -accesskey => 'G',
+                         -override  => '1');
+
    $html =~ s/\@\@\@YEARFIELD\@\@\@/$lang_text{'calfmt_year'}/g;
    $html =~ s/\@\@\@YEAR\@\@\@/ $temphtml /;
 
    $temphtml = end_form();
    $html =~ s/\@\@\@ENDFORM\@\@\@/$temphtml/g;
 
-   my $cal_url=qq|$config{'ow_cgiurl'}/openwebmail-cal.pl?sessionid=$thissession&amp;folder=$escapedfolder&amp;message_id=$escapedmessageid&amp;|;
 
-   $temphtml  = iconlink("yearview.gif", "$lang_calendar{'yearview'} ".formatted_date($year), qq|accesskey="Y" href="|.$cal_url.qq|action=calyear&year=$year"|);
-   $temphtml .= iconlink("monthview.gif", "$lang_calendar{'monthview'} ".formatted_date($year,$month), qq|accesskey="M" href="|.$cal_url.qq|action=calmonth&year=$year&month=$month"|);
-   $temphtml .= iconlink("weekview.gif", "$lang_calendar{'weekview'} ".formatted_date($year,$month,$day), qq|accesskey="W" href="|.$cal_url.qq|action=calweek&year=$year&month=$month&day=$day"|);
-   $temphtml .= iconlink("dayview.gif", "$lang_calendar{'dayview'} ".formatted_date($year,$month,$day), qq|accesskey="T" href="|.$cal_url.qq|action=calday&year=$year&month=$month&day=$day"|);
-   $temphtml .= iconlink("listview.gif", "$lang_calendar{'listview'} ".formatted_date($year), qq|accesskey="L" href="|.$cal_url.qq|action=callist&year=$year"|);
-   if ($year!=$current_year || $month!=$current_month || $day!=$current_day) {
-      $temphtml .= iconlink("refresh.gif", "$lang_text{'backto'} ".formatted_date($current_year,$current_month,$current_day), qq|accesskey="R" href="|.$cal_url.qq|action=calday&year=$current_year&month=$current_month&day=$current_day"|);
+
+   my $cal_url = qq|$config{'ow_cgiurl'}/openwebmail-cal.pl?|.
+                 qq|sessionid=$thissession&amp;folder=$escapedfolder&amp;message_id=$escapedmessageid&amp;|;
+
+   $temphtml  = iconlink("yearview.gif", "$lang_calendar{'yearview'} ".
+                  formatted_date($year),
+                  qq|accesskey="Y" href="|.$cal_url.qq|action=calyear&year=$year"|);
+   $temphtml .= iconlink("monthview.gif", "$lang_calendar{'monthview'} ".
+                  formatted_date($year,$month),
+                  qq|accesskey="M" href="|.$cal_url.qq|action=calmonth&year=$year&month=$month"|);
+   $temphtml .= iconlink("weekview.gif", "$lang_calendar{'weekview'} ".
+                  formatted_date($year,$month,$day),
+                  qq|accesskey="W" href="|.$cal_url.qq|action=calweek&year=$year&month=$month&day=$day"|);
+   $temphtml .= iconlink("dayview.gif", "$lang_calendar{'dayview'} ".
+                  formatted_date($year,$month,$day),
+                  qq|accesskey="T" href="|.$cal_url.qq|action=calday&year=$year&month=$month&day=$day"|);
+   $temphtml .= iconlink("listview.gif", "$lang_calendar{'listview'} ".
+                  formatted_date($year),
+                  qq|accesskey="L" href="|.$cal_url.qq|action=callist&year=$year"|);
+
+   if ($year != $current_year || $month != $current_month || $day != $current_day) {
+      $temphtml .= iconlink("refresh.gif", "$lang_text{'backto'} ".
+                     formatted_date($current_year,$current_month,$current_day),
+                     qq|accesskey="R" href="|.$cal_url.qq|action=calday&year=$current_year&month=$current_month&day=$current_day"|);
    }
+
    $temphtml .= "&nbsp;\n$miscbuttonsstr";
    $html =~ s/\@\@\@MENUBARLINKS\@\@\@/$temphtml/g;
 
@@ -814,13 +844,17 @@
    my ($prev_year, $prev_month, $prev_day)=(localtime($time-86400))[5,4,3];
    $prev_year+=1900; $prev_month++;
    my $gif="left.gif"; $gif="right.gif" if (is_RTLmode($prefs{'language'}));
-   $temphtml=iconlink($gif, formatted_date($prev_year,$prev_month,$prev_day), qq|accesskey="U" href="|.$cal_url.qq|action=calday&year=$prev_year&month=$prev_month&day=$prev_day"|). qq| \n|;
+   $temphtml = iconlink($gif, formatted_date($prev_year,$prev_month,$prev_day),
+                 qq|accesskey="U" href="|.$cal_url.qq|action=calday&year=$prev_year&month=$prev_month&day=$prev_day"|).
+                 qq| \n|;
    $html =~ s/\@\@\@PREV_LINK\@\@\@/$temphtml/g;
 
    my ($next_year, $next_month, $next_day)=(localtime($time+86400))[5,4,3];
    $next_year+=1900; $next_month++;
    $gif="right.gif"; $gif="left.gif" if (is_RTLmode($prefs{'language'}));
-   $temphtml=iconlink($gif, formatted_date($next_year,$next_month,$next_day), qq|accesskey="D" href="|.$cal_url.qq|action=calday&year=$next_year&month=$next_month&day=$next_day"|). qq| \n|;
+   $temphtml = iconlink($gif, formatted_date($next_year,$next_month,$next_day),
+                 qq|accesskey="D" href="|.$cal_url.qq|action=calday&year=$next_year&month=$next_month&day=$next_day"|).
+                 qq| \n|;
    $html =~ s/\@\@\@NEXT_LINK\@\@\@/$temphtml/g;
 
 
@@ -839,76 +873,245 @@
 
    $temphtml = formatted_date($year, $month, $day, $wdaynum);
    if ($prefs{'charset'} eq "big5" || $prefs{'charset'} eq "gb2312") {
-      $temphtml .= qq| &nbsp; |.lunar_str($year, $month, $day, $prefs{'charset'});
+      $temphtml .= qq| &nbsp; |.
+                   lunar_str($year, $month, $day, $prefs{'charset'});
    }
    $html =~ s/\@\@\@CALTITLE\@\@\@/$temphtml/g;
 
-   my $dow=$wdaystr[$wdaynum];
-   my $date=sprintf("%04d%02d%02d", $year, $month, $day);
-   my $date2=sprintf("%04d,%02d,%02d,%s", $year,$month,$day,$dow);
-   my @indexlist=();
+   # Find all indexes that take place today and sort them by starthourmin
+   my $dow       = $wdaystr[$wdaynum];
+   my $date      = sprintf("%04d%02d%02d", $year, $month, $day);
+   my $date2     = sprintf("%04d,%02d,%02d,%s", $year,$month,$day,$dow);
+   my @indexlist = (); # an index list of how many events occur on this day
+
    push(@indexlist, @{$indexes{$date}}) if (defined($indexes{$date}));
    push(@indexlist, @{$indexes{'*'}})   if (defined($indexes{'*'}));
-   @indexlist=sort { ($items{$a}{'starthourmin'}||1E9)<=>($items{$b}{'starthourmin'}||1E9) } @indexlist;
+
+   @indexlist    = sort { ($items{$a}{'starthourmin'}||1E9)<=>($items{$b}{'starthourmin'}||1E9) } @indexlist;
 
    my @bgcolor=($style{"tablerow_dark"}, $style{"tablerow_light"});
    my $colornum=0;
-   my $itemcount=0;
    $temphtml='';
-   for (my $t=0; $t<2400; $t+=100) {
-      my $timestr=hourmin2str(sprintf("%04d",$t), $prefs{'hourformat'});
-      my $y = 0;
-      for my $index (@indexlist) {
-         next if ($items{$index}{'starthourmin'} eq "0"|| !$index); # find timed items
-         if ($date=~/$items{$index}{'idate'}/ ||
-             $date2=~/$items{$index}{'idate'}/) {
-            if ($items{$index}{'starthourmin'}>=$t && $items{$index}{'starthourmin'}< $t+100 ) {
-               if (!$y) {
-                  $colornum=($colornum+1)%2;
-                  $temphtml .= qq|<tr>|.
-                               qq|<td bgcolor=$bgcolor[$colornum] align="right" nowrap>$timestr</td>|.
-                               qq|<td bgcolor=$bgcolor[$colornum]>|.
-                               qq|<table width="100%" border="0" cellpadding="2" cellspacing="0">\n|;
-               }
-               $temphtml .= dayview_table_item($items{$index}, $cal_url, "&year=$year&month=$month&day=$day&index=$index", ($index>=1E6));
-               $itemcount++;
-               $y++;
-            }
-         }
+
+   # begin the matrix routines
+   my (%thisday, @all_day_events, @event_matrix);
+   build_day_event_matrix(\%items, \@indexlist, \%thisday, \@all_day_events, \@event_matrix, $year, $month, $day);
+
+   $colornum=($colornum+1)%2; # alternate the bgcolor
+   $temphtml .= qq|<tr>|.
+                qq|<td colspan="2">|.
+                  qq|<!-- THE OUTSIDE-MOST TABLE DECLARATION FOR OUR CALENDAR DATA -->|.
+                  qq|<table width="100%" cellpadding="0" cellspacing="1" border="0">\n|.
+                  qq|<!-- BEGIN LISTING ALL DAY EVENTS -->|.
+                  qq|<tr>|.
+                  qq|<td width="10%" bgcolor=$bgcolor[$colornum] align="right" nowrap>All day</td>|.
+                  qq|<td width="90%" bgcolor=$bgcolor[$colornum] colspan="$thisday{'span'}">|.
+                    qq|<table width="100%" cellpadding="0" cellspacing="0">\n|; 
+
+   my ($bgcolor, $bordercolor, $eventemail, $eventlink, $eventstart, $eventend, $eventtime);
+
+   for my $event (@all_day_events) {
+       # we do the all day events first because they're the easiest
+       $eventemail = '';
+       $eventlink  = '';
+
+       $eventstart = hourmin2str(${$event}->{'starthourmin'}, $prefs{'hourformat'});
+       $eventend   = hourmin2str(${$event}->{'endhourmin'}, $prefs{'hourformat'});
+       $eventstart =~ s/ |\:00//g; # trim off :00 for more compact display
+       $eventend   =~ s/ |\:00//g;
+
+       if (${$event}->{'untimed'}) {
+          $eventtime = qq|$lang_text{'none'}-$lang_text{'none'}<b>:</b>&nbsp;|;
+       } else {
+          $eventtime = qq|$eventstart-$eventend<b>:</b>&nbsp;|;
+       }
+       if (${$event}->{'eventcolor'} eq "none") {
+          $bgcolor     = "#fdffc9";
+          $bordercolor = "#ff9999";
+       } else {
+          $bgcolor = "#" . $eventcolors{${$event}->{'eventcolor'}};
+          $bordercolor = "#" . bordercolor($eventcolors{${$event}->{'eventcolor'}});
+       }
+       if (${$event}->{'email'}) {
+          $eventemail = qq|&nbsp;|. iconlink("email.gif", "${$event}->{'email'}", "");
+       }
+       if (${$event}->{'link'}) {
+          $eventlink = qq|&nbsp;|. iconlink("cal-link.gif", "${$event}->{'link'}", "href=\"${$event}->{'link'}\" target=\"_blank\"");
+       }
+       if (${$event}->{'idate'} =~ m/[\*|,|\|]/) {
+          ${$event}->{'recurring'} = qq|onclick="return confirm('$lang_text{'multieditconf'}')"|;
+       }
+
+       $temphtml .=  qq|<tr>|.
+                     qq|<td bgcolor=$bgcolor[$colornum] valign="top" colspan="$thisday{'span'}">|.
+                       qq|<table width="100%" style="border-width: 2px; border-style: solid; border-color: $bordercolor;" cellpadding="2" cellspacing="0">\n|.
+                       qq|<tr>|.
+
+                         qq|<td bgcolor=$bgcolor valign="top" align="left">|.
+                         qq|<a accesskey="E" href="$cal_url|.
+                         qq|action=caledit&year=$year&month=$month&day=$day&index=${$event}->{'index'}" ${$event}->{'recurring'}>|.
+                         qq|$eventtime${$event}->{'string'}</a>|.
+                         qq|&nbsp;&nbsp;|. iconlink("cal-delete.gif", "$lang_text{'delete'}", "href=${cal_url}action=caldel&year=$year&month=$month&day=$day&index=${$event}->{'index'} ${$event}->{'recurring'}").
+                         $eventlink.
+                         $eventemail.
+                         qq|</td>|.
+
+                       qq|</tr>|.
+                       qq|</table>|.
+                     qq|</td>|.
+                     qq|</tr>|;
+   }
+
+   if (@all_day_events == 0) {
+      $temphtml .= qq|<tr><td bgcolor=$bgcolor[$colornum]>&nbsp;</td></tr>|;
+   }
+
+   $temphtml .= qq|</table>|.
+                qq|</td>|.
+                qq|</tr>|.
+                qq|<!--END OF ALL DAY LISTINGS-->|;
+
+
+
+   $temphtml .= qq|<!--START EVENT MATRIX-->|;
+   my ($started, $colspan, $start, $daystartepoch, $thisHHMM);
+   my @pos = ();
+
+   for (my $i = 0; $i < 48; $i++) {
+      if ($i >= ((($prefs{'calendar_endhour'} / 100) * 2) + 2 ) && $i > $thisday{'last'}) {
+         last;
+      }
+      if (!$started && $i < (($prefs{'calendar_starthour'} / 100) * 2) && $event_matrix[$i] == 0) {
+         next;
+      }
+      if ($i >= ((($prefs{'calendar_endhour'} / 100) * 2) + 2 ) ) {
+         next;
       }
-      $temphtml .= qq|</table></td></tr>\n| if $y;
 
-      if (!$y && $prefs{'calendar_showemptyhours'} &&
-          $t>=$prefs{'calendar_starthour'} && $t<=$prefs{'calendar_endhour'}) {
-         $colornum=($colornum+1)%2;
-         $temphtml .= qq|<tr><td bgcolor=$bgcolor[$colornum] align="right" nowrap>$timestr</td>|.
-                      qq|<td bgcolor=$bgcolor[$colornum]>&nbsp;</td></tr>\n|;
+      $eventemail    = '';
+      $eventlink     = '';
+      $start         = timelocal(0, ($i % 2) * 30, floor($i/2), $day, $month-1, $year-1900); # this 30 min epoch
+      $thisHHMM      = sprintf("%02d", floor($i/2)) . sprintf("%02d", ($i % 2) * 30);
+      $started       = 1;
+      $colspan       = 0;
+      $daystartepoch = timelocal(0, 0, 0, $day, $month-1, $year-1900);
+
+      if (!($i % 2) && $i >= (($prefs{'calendar_starthour'} / 100) * 2) && $i <= ((($prefs{'calendar_endhour'} / 100) * 2) + 2) ) {
+          # start html for a full row
+          $colornum  = ($colornum+1)%2; # alternate the bgcolor
+          $temphtml .= qq|<tr>|.
+                       qq|<td width="10%" bgcolor=$bgcolor[$colornum] align="right" nowrap>|.
+                         hourmin2str($thisHHMM, $prefs{'hourformat'}).
+                       qq|</td>|;
+      } elsif ($i % 2 && $i >= (($prefs{'calendar_starthour'} / 100) * 2) && $i <= ((($prefs{'calendar_endhour'} / 100) * 2) + 2)) {
+          # start html for a half row
+          $temphtml .= qq|<tr>|.
+                       qq|<td width="1%" bgcolor=$bgcolor[$colornum]>&nbsp;</td>|;
       }
-   }
 
-   my $y = 0;
-   for my $index (@indexlist) {
-      next if ($items{$index}{'starthourmin'} ne "0"|| !$index); # find non-timed items
-      if ($date=~/$items{$index}{'idate'}/ ||
-          $date2=~/$items{$index}{'idate'}/) {
-         if (!$y) {
-            $colornum=($colornum+1)%2;
-            $temphtml .= qq|<tr>|.
-                         qq|<td bgcolor=$bgcolor[$colornum]>&nbsp;</td>|.
-                         qq|<td bgcolor=$bgcolor[$colornum]>|.
-                         qq|<table width="100%" border="0" cellpadding="2" cellspacing="0">\n|;
+      if ($event_matrix[$i]) {
+         # There is some sort of event during this timeslot
+         # so lets populate all the timeslots
+         foreach my $vpos (0..($thisday{'span'} - 1)) {
+            my $hpos = $i;
+
+            if ($event_matrix[$hpos][$vpos]) {
+               # there is an event at this position
+               my $event = ${$event_matrix[$hpos][$vpos]};
+
+               if ($pos[$hpos][$vpos] == 0 && $event->{'started'} == 0) {
+                  # we have not drawn on this position
+                  # we have not drawn anything for this event
+                  # so this event must start here
+                  $event->{'started'} = 1;
+                  $colspan = $thisday{'span'} - $event->{'colspan'} + 1;
+
+                  if ($event->{'eventcolor'} eq "none") {
+                     $bgcolor     = "#fdffc9";
+                     $bordercolor = "#ff9999";
+                  } else {
+                     $bgcolor     = "#" . $eventcolors{$event->{'eventcolor'}};
+                     $bordercolor = "#" . bordercolor($eventcolors{$event->{'eventcolor'}});
+                  }
+                  if ($event->{'email'}) {
+                     $eventemail = qq|&nbsp;|. iconlink("email.gif", "$event->{'email'}", "");
+                  }
+                  if ($event->{'link'}) {
+                     $eventlink = qq|&nbsp;|. iconlink("cal-link.gif", "$event->{'link'}", "href=\"$event->{'link'}\" target=\"_blank\"");
+                  }
+                  if ($event->{'idate'} =~ m/[\*|,|\|]/) {
+                     $event->{'recurring'} = qq|onclick="return confirm('$lang_text{'multieditconf'}')"|;
+                  }
+                  while ( $event->{'rowspan'} + $i  > ((($prefs{'calendar_endhour'} / 100) * 2) + 2) ) {
+                     $event->{'rowspan'}--;
+                  }
+
+                  $temphtml .= qq|<td bgcolor=$bgcolor style="border-width: 2px; border-style: solid; border-color: $bordercolor;" valign="top" width="|.
+                               int(100 * ($colspan / $thisday{'span'})).
+                               qq|%" colspan="$colspan" rowspan="$event->{'rowspan'}">|.
+                               qq|<a accesskey="E" href="$cal_url|.
+                               qq|action=caledit&year=$year&month=$month&day=$day&index=$event->{'index'}" $event->{'recurring'}>|.
+                               qq|$event->{'string'}</a>|.
+                               qq|&nbsp;&nbsp;|. iconlink("cal-delete.gif", "$lang_text{'delete'}", "href=${cal_url}action=caldel&year=$year&month=$month&day=$day&index=$event->{'index'}").
+                               $eventlink.
+                               $eventemail.
+                               qq|</td>|;
+
+                  # mark drawn all the columns and rows this event occurs in
+                  my $eventendcolumn = $vpos + $colspan - 1;
+                  foreach my $col ($vpos..($eventendcolumn * ($eventendcolumn <=> 0))) {
+                     foreach my $row (0..($event->{'rowspan'} - 1)) {
+                        if ($row > 0) {
+                           $hpos++;
+                           $pos[$hpos][$col]++;
+                        } else {
+                           $pos[$hpos][$col]++;
+                        }
+                     }
+                     $hpos = $i;
+                  }
+               } elsif ($pos[$hpos][$vpos] == 0 && $event->{'started'} == 1) {
+                  # There is an event here but nothing has been drawn here 
+                  # because something was already drawn for this event (in another column probably)
+                  $temphtml .= qq|<td bgcolor=$bgcolor[$colornum]>&nbsp;</td>|;
+                  $pos[$hpos][$vpos]++;
+               } else {
+                  # Do nothing, we already drew something here
+               }
+            } else {
+               # There is no event here
+               if ($pos[$hpos][$vpos] != 1) {
+                  # and we didn't draw here
+                  $temphtml .= qq|<td bgcolor=$bgcolor[$colornum]>&nbsp;</td>|;
+                  $pos[$hpos][$vpos]++;
+               }
+            }
+         }
+      } else {
+         # There are no events during this timeslot.
+         # Plug any gaps with filler
+         foreach my $vpos (0..($thisday{'span'} - 1)) {
+            if ($pos[$i][$vpos] != 1) {
+               $temphtml .= qq|<td bgcolor=$bgcolor[$colornum]>&nbsp;</td>|;
+               $pos[$i][$vpos]++;
+            }
          }
-         $temphtml .= dayview_table_item($items{$index}, $cal_url, "&year=$year&month=$month&day=$day&index=$index", ($index>=1E6));
-         $itemcount++;
-         $y++;
       }
+
+     $temphtml .= qq|</tr>|;
    }
-   $temphtml .= qq|</table></td></tr>\n| if $y;
 
-   if ($itemcount==0) {
+   if (@indexlist == 0) {
       $colornum=($colornum+1)%2;
-      $temphtml .= qq|<tr><td bgcolor=$bgcolor[$colornum]>&nbsp;</td><td align=center bgcolor=$bgcolor[$colornum]>$lang_text{'noitemforthisday'}</td></tr>\n|;
+      $temphtml .= qq|<tr>|.
+                   qq|<td bgcolor=$bgcolor[$colornum]>&nbsp;</td>|.
+                   qq|<td align=center bgcolor=$bgcolor[$colornum]>$lang_text{'noitemforthisday'}</td>|.
+                   qq|</tr>|;
    }
+
+   $temphtml .= qq|</table></td></tr>\n|;
+
+
    $html =~ s/\@\@\@CALENDARITEMS\@\@\@/$temphtml/;
 
    $temphtml = startform(-action=>"$config{'ow_cgiurl'}/openwebmail-cal.pl",
@@ -1104,59 +1307,192 @@
    printfooter(2);
 }
 
-# print an item in the day view table
-sub dayview_table_item {
-   my ($r_item, $cal_url, $cgi_parm, $is_global) = @_;
-   my $timestr='';
-   my $emailimgstr='';
-
-   my $colorstr='';
-   if (defined($eventcolors{${$r_item}{'eventcolor'}})) {
-      $colorstr=qq|bgcolor="#$eventcolors{${$r_item}{'eventcolor'}}"|;
+sub build_day_event_matrix {
+   # This function builds a matrix of the events of the day.
+   # This matrix is used to determine how the table should be
+   # formed and printed. 
+   my($r_items, $r_indexlist, $r_thisday, $r_all_day_events, $r_event_matrix, $iyear, $imonth, $iday) = @_;
+   my @event_arr = (); # to store events that are not "all-day"
+   my $maxspan   = 1;
+   my $last      = 0;
+
+   # split the events into two lists: all day events, and not all day events.
+   foreach my $index (@{$r_indexlist}) {
+      ${$r_items}{$index}{'index'} = $index; #remember the index for later
+      if (is_all_day(\${$r_items}{$index})) {
+          if (${$r_items}{$index}{'starthourmin'} == 0 && ${$r_items}{$index}{'endhourmin'} == 0) {
+             ${$r_items}{$index}{'untimed'} = 1;
+          }
+          push(@{$r_all_day_events}, \${$r_items}{$index});
+      } else {
+          # Format the start and end times to epoch time
+          my ($istarthour, $istartmin)      = ${$r_items}{$index}{'starthourmin'} =~ /^(..)(..)$/;
+          my ($iendhour, $iendmin)          = ${$r_items}{$index}{'endhourmin'} =~ /^(..)(..)$/;
+          ${$r_items}{$index}{'startepoch'} = timelocal(0,$istartmin,$istarthour,$iday,$imonth-1,$iyear-1900); 
+          ${$r_items}{$index}{'endepoch'}   = timelocal(0,$iendmin,$iendhour,$iday,$imonth-1,$iyear-1900);
+          push(@event_arr, \${$r_items}{$index});
+      }
    }
 
-   my $temphtml=qq|<tr $colorstr valign=top>|;
+   for (my $i = 0; $i < 48; $i++) {
+      # There are 48 half hours in a day. We will build a matrix based on when events occur.
+      my $start = timelocal(0, ($i % 2) * 30, floor($i/2), $day, $month-1, $year-1900); # Each 30 min start time
+      my $x = 0;
+      foreach my $event (@event_arr) {
+         if (${$event}->{'endepoch'} > $start && ${$event}->{'startepoch'} < $start + 30 * 60) {
+            # This event occurs within this 30 min window
+            if ($i > ${$r_thisday}{'last'}) {
+               ${$r_thisday}{'last'} = $i;
+            }
 
-   if (${$r_item}{'starthourmin'} ne "0") {
-      $timestr = hourmin2str(${$r_item}{'starthourmin'}, $prefs{'hourformat'});
-      if (${$r_item}{'endhourmin'} ne "0") {
-         $timestr .= qq|-| . hourmin2str(${$r_item}{'endhourmin'}, $prefs{'hourformat'});
+            ${$r_event_matrix}[$i][$x] = $event;
+            $x++;
+
+            if (${$event}->{'rowspan'}) {
+               ${$event}->{'rowspan'}++;
+            } else {
+               ${$event}->{'rowspan'} = 1;
+            }
+
+            # calculate the colspan of this event
+            foreach my $ev (@{${$r_event_matrix}[$i]}) {
+               if ((not ${$ev}->{'colspan'}) || (@{${$r_event_matrix}[$i]} > ${$ev}->{'colspan'})) {
+                  # set colspan to num of elements in this 30 min block
+                  ${$ev}->{'colspan'} = @{${$r_event_matrix}[$i]};
+               }
+            }
+
+            if ($maxspan < @{${$r_event_matrix}[$i]}) {
+               $maxspan = @{${$r_event_matrix}[$i]};
+            }
+         }
       }
    }
-   $timestr = "<font color=#c00000>$timestr</font>" if ($timestr ne "");
 
-   if ($config{'calendar_email_notifyinterval'}>0 && ${$r_item}{'email'}) {
-      $emailimgstr=qq|&nbsp;|. iconlink("email.gif", "${$r_item}{'email'}", ""). qq|\n|;
+   ${$r_thisday}{'span'}  = $maxspan;
+   ${$r_thisday}{'built'} = 1;
+}
+
+sub floor {
+   # implements a C style floor().
+   # floor($num) returns the largest integer not greater than $num
+   my $num = shift;
+   my $newnum;
+
+   $newnum = int($num + .5 * ($num <=> 0)); 
+   while ($newnum > $num) {
+      $newnum--;
    }
 
-   if (${$r_item}{'string'}) {
-      if (${$r_item}{'link'} eq "0") {
-         $temphtml .= qq|<td $colorstr>$timestr ${$r_item}{'string'}$emailimgstr</td>\n|;
-      } else {
-         my $link=${$r_item}{'link'}; $link=~s/\%THISSESSION\%/$thissession/;
-         $temphtml .= qq|<td $colorstr>$timestr <a href="$link" target="_blank">${$r_item}{'string'}</a>$emailimgstr</td>\n|;
-      }
+   return $newnum;
+}
+
+sub is_all_day {
+   # returns true if the event is all day long
+   my $item = shift;
+
+   if ((${$item}->{'starthourmin'} <= $prefs{'calendar_starthour'} && (${$item}->{'endhourmin'} >= $prefs{'calendar_endhour'} || ${$item}->{'endhourmin'} < ${$item}->{'starthourmin'})) || (${$item}->{'starthourmin'} == 0 && ${$item}->{'endhourmin'} == 0)) {
+      return 1;
    } else {
-      $temphtml .= qq|<td $colorstr>&nbsp;</td>\n|;
+      return 0;
    }
+}
+ 
+sub bordercolor {
+   # take a hex number and calculate a hex number that
+   # will be a nice complement to it as a bordercolor
+   my ($redhex, $greenhex, $bluehex) = $_[0] =~ m/(..)(..)(..)/;
+   my ($r, $g, $blue) = (sprintf("%d", hex($redhex)), sprintf("%d", hex($greenhex)), sprintf("%d", hex($bluehex)));
+   my ($h, $s, $v) = rgb2hsv($r, $g, $blue);
+
+   # adjust to get our new hsv bordercolor
+   if ($s > .5) { $s -= .15; $v += 30; } else { $s += .15; $v -= 30; };
+   $s = 0 if ($s < 0);
+   $s = 1 if ($s > 1);
+   $v = 0 if ($v < 0);
+   $v = 255 if ($v > 255);
 
-   my $right='right'; $right='left' if (is_RTLmode($prefs{'language'}));
-   if ($is_global) {
-      $temphtml .= "<td $colorstr>&nbsp;</td>\n";
-   } elsif (${$r_item}{'idate'} =~ /[^\d]/) {
-      $temphtml .= qq|<td align="$right" nowrap $colorstr>\n|.
-                   qq|<a accesskey="E" href="$cal_url|.qq|action=caledit$cgi_parm" onclick="return confirm('$lang_text{'multieditconf'}')">[$lang_text{'edit'}]</a>\n|.
-                   qq|<a href="$cal_url|.qq|action=caldel$cgi_parm" onclick="return confirm('$lang_text{'multidelconf'}')">[$lang_text{'delete'}]</a>\n|.
-                   qq|</td>\n|;
+   ($r, $g, $blue) = hsv2rgb($h, $s, $v);
+   ($redhex, $greenhex, $bluehex) = (sprintf("%02x", $r), sprintf("%02x", $g), sprintf("%02x", $blue));
+
+   return "$redhex$greenhex$bluehex";
+}
+
+sub rgb2hsv {
+   # based off reference code at http://www.cs.rit.edu/~ncs/color/t_convert.html
+   my ($r, $g, $blue) = @_;
+   my ($h, $s, $v, $min, $max, $delta);
+
+   ($min, $max) = (sort { $a <=> $b } ($r,$g,$blue))[0,-1];
+   $v = $max;
+
+   $delta = $max - $min;
+
+   if ($max != 0 ) {
+      $s = $delta / $max;
    } else {
-      $temphtml .= qq|<td align="$right" nowrap $colorstr>\n|.
-                   qq|<a accesskey="E" href="$cal_url|.qq|action=caledit$cgi_parm">[$lang_text{'edit'}]</a>\n|.
-                   qq|<a href="$cal_url|.qq|action=caldel$cgi_parm">[$lang_text{'delete'}]</a>\n|.
-                   qq|</td>\n|;
+      return(-1, 0, 0); # r g b are all 0
+   }
+
+   if ($r == $max) {
+      $h = ($g - $blue) / $delta;
+   } elsif ($g == $max) {
+      $h = 2 + ($blue - $r) / $delta;
+   } else {
+      $h = 4 + ($r - $g) / $delta;
+   }
+
+   $h *= 60;
+   if ($h < 0) {
+      $h += 360;
+   }
+
+   return ($h, $s, $v);
+}
+
+sub hsv2rgb {
+   # based off reference code at http://www.cs.rit.edu/~ncs/color/t_convert.html 
+   my ($h, $s, $v) = @_;
+   my ($i, $f, $p, $q, $t, $r, $g, $blue);
+
+   if ($s == 0) {
+      return ($v, $v, $v); # achromatic
+   }
+
+   $h /= 60; # sector 0 to 5
+   $i = floor($h);
+   $f = $h - $i;
+   $p = $v * (1 - $s);
+   $q = $v * (1 - $s * $f);
+   $t = $v * (1 - $s * (1 - $f));
+
+   if ($i == 0) {
+      $r = $v;
+      $g = $t;
+      $blue = $p;
+   } elsif ($i == 1) {
+      $r = $q;
+      $g = $v;
+      $blue = $p;
+   } elsif ($i == 2) {
+      $r = $p;
+      $g = $v;
+      $blue = $t;
+   } elsif ($i == 3) {
+      $r = $p;
+      $g = $q;
+      $blue = $v;
+   } elsif ($i == 4) {
+      $r = $t;
+      $g = $p;
+      $blue = $v;
+   } else {
+      $r = $v;
+      $g = $p;
+      $blue = $q;
    }
-   $temphtml .= qq|</tr>|;
 
-   return $temphtml;
+   return ($r, $g, $blue);
 }
 ######################## END DAYVIEW #########################
 
@@ -1869,7 +2205,7 @@
          $hourmin =~ s/\@\@\@HOURMIN\@\@\@/$hour:$min/;
          $hourmin =~ s/\@\@\@AMPM\@\@\@/$lang_text{$ampm}/;
       } else {
-         $hourmin = "$hour:$min";
+         $hourmin = sprintf("%02d", $hour) . ":" . sprintf("%02d", $min);
       }
    }
    return $hourmin;
