Back to index

lightning-sunbird  0.9+nobinonly
icalspanlist.c
Go to the documentation of this file.
00001 /* -*- Mode: C -*-
00002     ======================================================================
00003     FILE: icalspanlist.c
00004     CREATOR: ebusboom 23 aug 2000
00005   
00006     $Id: icalspanlist.c,v 1.13 2002/10/30 23:41:47 acampi Exp $
00007     $Locker:  $
00008     
00009     (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
00010     
00011     This program is free software; you can redistribute it and/or modify
00012     it under the terms of either: 
00013     
00014     The LGPL as published by the Free Software Foundation, version
00015     2.1, available at: http://www.fsf.org/copyleft/lesser.html
00016     
00017     Or:
00018     
00019     The Mozilla Public License Version 1.0. You may obtain a copy of
00020     the License at http://www.mozilla.org/MPL/
00021 
00022 
00023     ======================================================================*/
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028 
00029 #include "ical.h"
00030 #include "icalspanlist.h"
00031 
00032 #include <stdlib.h> /* for free and malloc */
00033 #include <string.h>
00034 
00035 struct icalspanlist_impl {
00036   pvl_list spans;           
00037   struct icaltimetype start;    
00038   struct icaltimetype end;  
00039 };
00040 
00051 static int compare_span(void* a, void* b)
00052 {
00053     struct icaltime_span *span_a = (struct icaltime_span *)a ;
00054     struct icaltime_span *span_b = (struct icaltime_span *)b ;
00055     
00056     if(span_a->start == span_b->start){
00057        return 0;
00058     } else if(span_a->start < span_b->start){
00059        return -1;
00060     }  else { /*if(span_a->start > span->b.start)*/
00061        return 1;
00062     }
00063 }
00064 
00065 
00077 static void icalspanlist_new_callback(icalcomponent *comp,
00078                                        struct icaltime_span *span,
00079                                        void *data)
00080 {
00081   icaltime_span *s;
00082   icalspanlist *sl = (icalspanlist*) data;
00083 
00084   if (span->is_busy == 0)
00085     return;
00086 
00087   if ((s=(icaltime_span *) malloc(sizeof(icaltime_span))) == 0) {
00088     icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00089     return;
00090   }
00091 
00093   *s = *span;
00094   pvl_insert_ordered(sl->spans, compare_span, (void*)s);
00095 }
00096                                        
00097 
00098 
00111 icalspanlist* icalspanlist_new(icalset *set, 
00112                             struct icaltimetype start,
00113                             struct icaltimetype end)
00114 {
00115     struct icaltime_span range;
00116     pvl_elem itr;
00117     icalcomponent *c,*inner;
00118     icalcomponent_kind kind, inner_kind;
00119     icalspanlist *sl; 
00120     struct icaltime_span *freetime;
00121 
00122     if ( ( sl = (struct icalspanlist_impl*)
00123           malloc(sizeof(struct icalspanlist_impl))) == 0) {
00124        icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00125        return 0;
00126     }
00127 
00128     sl->spans =  pvl_newlist();
00129     sl->start =  start;
00130     sl->end   =  end;
00131 
00132     range.start = icaltime_as_timet(start);
00133     range.end = icaltime_as_timet(end);
00134 
00135     /* Get a list of spans of busy time from the events in the set
00136        and order the spans based on the start time */
00137 
00138    for(c = icalset_get_first_component(set);
00139        c != 0;
00140        c = icalset_get_next_component(set)){
00141 
00142        kind  = icalcomponent_isa(c);
00143        inner = icalcomponent_get_inner(c);
00144 
00145        if(!inner){
00146           continue;
00147        }
00148 
00149        inner_kind = icalcomponent_isa(inner);
00150 
00151        if( kind != ICAL_VEVENT_COMPONENT &&
00152           inner_kind != ICAL_VEVENT_COMPONENT){
00153           continue;
00154        }
00155        
00156        icalerror_clear_errno();
00157        
00158        icalcomponent_foreach_recurrence(c, start, end, 
00159                                    icalspanlist_new_callback, 
00160                                    (void*)sl);
00161        
00162    }
00163     
00164     /* Now Fill in the free time spans. loop through the spans. if the
00165        start of the range is not within the span, create a free entry
00166        that runs from the start of the range to the start of the
00167        span. */
00168 
00169      for( itr = pvl_head(sl->spans);
00170         itr != 0;
00171         itr = pvl_next(itr))
00172     {
00173        struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr);
00174 
00175        if ((freetime=(struct icaltime_span *)
00176             malloc(sizeof(struct icaltime_span))) == 0){
00177            icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00178            return 0;
00179            }
00180 
00181        if(range.start < s->start){
00182            freetime->start = range.start; 
00183            freetime->end = s->start;
00184            
00185            freetime->is_busy = 0;
00186 
00187 
00188            pvl_insert_ordered(sl->spans,compare_span,(void*)freetime);
00189        } else {
00190            free(freetime);
00191        }
00192        
00193        range.start = s->end;
00194     }
00195      
00196      /* If the end of the range is null, then assume that everything
00197         after the last item in the calendar is open and add a span
00198         that indicates this */
00199 
00200      if( icaltime_is_null_time(end)){
00201         struct icaltime_span* last_span;
00202 
00203         last_span = (struct icaltime_span*)pvl_data(pvl_tail(sl->spans));
00204 
00205         if (last_span != 0){
00206 
00207             if ((freetime=(struct icaltime_span *)
00208                 malloc(sizeof(struct icaltime_span))) == 0){
00209                icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00210                return 0;
00211             } 
00212        
00213             freetime->is_busy = 0;
00214             freetime->start = last_span->end;
00215             freetime->end = freetime->start;
00216             pvl_insert_ordered(sl->spans,compare_span,(void*)freetime);
00217         }
00218      }
00219 
00220 
00221      return sl;
00222 }
00223 
00230 void icalspanlist_free(icalspanlist* s)
00231 {
00232     struct icaltime_span *span;
00233 
00234     if (s == NULL)
00235       return;
00236 
00237     while( (span=pvl_pop(s->spans)) != 0){
00238        free(span);
00239     }
00240     
00241     pvl_free(s->spans);
00242     
00243     s->spans = 0;
00244 
00245     free(s);
00246 }
00247 
00248 
00253 void icalspanlist_dump(icalspanlist* sl){
00254      int i = 0;
00255      pvl_elem itr;
00256 
00257      for( itr = pvl_head(sl->spans);
00258         itr != 0;
00259         itr = pvl_next(itr))
00260     {
00261        struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr);
00262        
00263        printf("#%02d %d start: %s",++i,s->is_busy,ctime(&s->start));
00264        printf("      end  : %s",ctime(&s->end));
00265 
00266     }
00267 }
00268 
00269 icalcomponent* icalspanlist_make_free_list(icalspanlist* sl);
00270 icalcomponent* icalspanlist_make_busy_list(icalspanlist* sl);
00271 
00272 
00282 struct icalperiodtype icalspanlist_next_free_time(icalspanlist* sl,
00283                                           struct icaltimetype t)
00284 {
00285      pvl_elem itr;
00286      struct icalperiodtype period;
00287      struct icaltime_span *s;
00288 
00289      time_t rangett= icaltime_as_timet(t);
00290 
00291      period.start = icaltime_null_time();
00292      period.end = icaltime_null_time();
00293 
00294      itr = pvl_head(sl->spans);
00295      s = (struct icaltime_span *)pvl_data(itr);
00296 
00297      if (s == 0){
00298         /* No elements in span */
00299         return period;
00300      }
00301 
00302      /* Is the reference time before the first span? If so, assume
00303         that the reference time is free */
00304      if(rangett <s->start ){
00305         /* End of period is start of first span if span is busy, end
00306             of the span if it is free */
00307         period.start =  t;
00308 
00309         if (s->is_busy == 1){
00310             period.end =  icaltime_from_timet(s->start,0);
00311         } else {
00312             period.end =  icaltime_from_timet(s->end,0);
00313         }
00314 
00315         return period;
00316      }
00317 
00318      /* Otherwise, find the first free span that contains the
00319         reference time. */
00320      for( itr = pvl_head(sl->spans);
00321         itr != 0;
00322         itr = pvl_next(itr))
00323     {
00324        s = (struct icaltime_span *)pvl_data(itr);
00325 
00326        if(s->is_busy == 0 && s->start >= rangett && 
00327            ( rangett < s->end || s->end == s->start)){
00328 
00329            if (rangett < s->start){
00330               period.start = icaltime_from_timet(s->start,0);
00331            } else {
00332               period.start = icaltime_from_timet(rangett,0);
00333            }
00334            
00335            period.end = icaltime_from_timet(s->end,0);
00336 
00337            return period;
00338        }
00339                      
00340     }
00341 
00342      period.start = icaltime_null_time();
00343      period.end = icaltime_null_time();
00344 
00345      return period;
00346 }
00347 
00348 struct icalperiodtype icalspanlist_next_busy_time(icalspanlist* sl,
00349                                           struct icaltimetype t);
00350 
00351 
00372 int* icalspanlist_as_freebusy_matrix(icalspanlist* sl, int delta_t) {
00373   pvl_elem itr;
00374   int spanduration_secs;
00375   int *matrix;
00376   int matrix_slots;
00377   time_t sl_start, sl_end;
00378 
00379   icalerror_check_arg_rz( (sl!=0), "spanlist");
00380 
00381   if (!delta_t)
00382     delta_t = 3600;
00383 
00385   sl_start = icaltime_as_timet_with_zone(sl->start, icaltimezone_get_utc_timezone());
00386   sl_end   = icaltime_as_timet_with_zone(sl->end, icaltimezone_get_utc_timezone());
00387 
00388 
00392   sl_start /= delta_t;
00393   sl_start *= delta_t;
00394 
00395   sl_end /= delta_t;
00396   sl_end *= delta_t;
00397 
00398 
00400   spanduration_secs = sl_end - sl_start;
00401 
00402 
00404   matrix_slots = spanduration_secs/delta_t + 1;
00405 
00406   matrix = (int*) malloc(sizeof(int) * matrix_slots);
00407   if (matrix == NULL) {
00408     icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00409     return NULL;
00410   }
00411   memset(matrix, 0, sizeof(int) * matrix_slots);
00412   matrix[matrix_slots-1] = -1;
00413 
00414   /* loop through each span and mark the slots in the array */
00415 
00416   for( itr = pvl_head(sl->spans);  itr != 0;  itr = pvl_next(itr)) {
00417     struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr);
00418     
00419     if (s->is_busy == 1) {
00420       int offset_start = s->start/delta_t - sl_start/delta_t;
00421       int offset_end   = (s->end - 1) /delta_t  - sl_start/delta_t + 1;
00422       int i;
00423       
00424       if (offset_end >= matrix_slots)
00425        offset_end = matrix_slots - 1;
00426 
00427       i = offset_start;
00428       for (i=offset_start; i < offset_end; i++) {
00429        matrix[i]++;
00430       }
00431     }
00432   }
00433   return matrix;
00434 }
00435     
00436 
00452 icalcomponent *icalspanlist_as_vfreebusy(icalspanlist* sl,
00453                                     const char* organizer,
00454                                     const char* attendee) {
00455   icalcomponent *comp;
00456   icalproperty *p;
00457   struct icaltimetype atime = icaltime_from_timet( time(0),0);
00458   pvl_elem itr;
00459   icaltimezone *utc_zone;
00460   icalparameter *param;
00461 
00462   if (!attendee) {
00463     icalerror_set_errno(ICAL_USAGE_ERROR);
00464     return 0;
00465   }
00466 
00467   utc_zone = icaltimezone_get_utc_timezone ();
00468 
00469   comp = icalcomponent_new_vfreebusy();
00470   
00471   icalcomponent_add_property(comp, icalproperty_new_dtstart(sl->start));
00472   icalcomponent_add_property(comp, icalproperty_new_dtend(sl->end));
00473   icalcomponent_add_property(comp, icalproperty_new_dtstamp(atime));
00474 
00475   if (organizer) {
00476     icalcomponent_add_property(comp, icalproperty_new_organizer(organizer));
00477   }
00478   icalcomponent_add_property(comp, icalproperty_new_attendee(attendee));
00479 
00480   /* now add the freebusy sections.. */
00481 
00482   for( itr = pvl_head(sl->spans);  itr != 0;  itr = pvl_next(itr)) {
00483     struct icalperiodtype period;
00484     struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr);
00485 
00486     if (s->is_busy == 1) {
00487 
00488       period.start = icaltime_from_timet_with_zone (s->start, 0, utc_zone);
00489       period.end   = icaltime_from_timet_with_zone (s->end, 0, utc_zone);
00490       period.duration = icaldurationtype_null_duration();
00491 
00492 
00493       p = icalproperty_new_freebusy(period);
00494       param = icalparameter_new_fbtype(ICAL_FBTYPE_BUSY);
00495       icalproperty_add_parameter(p, param);
00496 
00497       icalcomponent_add_property(comp, p);
00498     }
00499     
00500   }
00501 
00502   return comp;
00503 }
00504 
00505 
00516 icalspanlist *icalspanlist_from_vfreebusy(icalcomponent* comp)
00517 {
00518   icalcomponent *inner;
00519   icalproperty  *prop;
00520   icalspanlist  *sl;
00521 
00522   icalerror_check_arg_rz((comp != NULL), "comp");
00523   
00524   inner = icalcomponent_get_inner(comp);
00525   if (!inner) return NULL;
00526 
00527   if ( ( sl = (icalspanlist*) malloc(sizeof(icalspanlist))) == 0) {
00528     icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00529     return 0;
00530   }
00531   sl->spans =  pvl_newlist();
00532 
00533   /* cycle through each FREEBUSY property, adding to the spanlist */
00534   for (prop = icalcomponent_get_first_property(inner, ICAL_FREEBUSY_PROPERTY);
00535        prop != NULL;
00536        prop = icalcomponent_get_next_property(inner, ICAL_FREEBUSY_PROPERTY)) {
00537     icaltime_span *s = (icaltime_span *) malloc(sizeof(icaltime_span));
00538     icalparameter *param;
00539     struct icalperiodtype period;
00540     icalparameter_fbtype fbtype;
00541 
00542     if (s == 0) {
00543       icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00544       return 0;
00545     }
00546     
00547     param = icalproperty_get_first_parameter(prop, ICAL_FBTYPE_PARAMETER);
00548     fbtype = (param) ? icalparameter_get_fbtype(param) : ICAL_FBTYPE_BUSY;
00549 
00550     switch (fbtype) {
00551     case ICAL_FBTYPE_FREE:
00552     case ICAL_FBTYPE_NONE:
00553     case ICAL_FBTYPE_X:
00554       s->is_busy = 1;
00555     default:
00556       s->is_busy = 0;
00557     }
00558     
00559     period = icalproperty_get_freebusy(prop);
00560     s->start = icaltime_as_timet_with_zone(period.start, icaltimezone_get_utc_timezone());
00561     s->end = icaltime_as_timet_with_zone(period.end, icaltimezone_get_utc_timezone());
00562 ;
00563     pvl_insert_ordered(sl->spans, compare_span, (void*)s);
00564   }
00566   return sl;
00567 }