pres_timer.c

00001 #include "presentity.h"
00002 #include "pa_mod.h"
00003 #include "ptime.h"
00004 #include "notify.h"
00005 #include "async_auth.h"
00006 #include "tuple.h"
00007 #include "pres_notes.h"
00008 #include "extension_elements.h"
00009 
00010 static void process_watchers(presentity_t* _p, int *changed)
00011 {
00012         watcher_t *next, *w;
00013         int presentity_changed;
00014         int notify;
00015         
00016         /* !!! "changed" is not initialized here it is only set if change
00017          * in presentity occurs */
00018         
00019         presentity_changed = _p->flags & PFLAG_PRESENCE_CHANGED;
00020 
00021         w = _p->first_watcher;
00022         while (w) {
00023                 /* changes status of expired watcher */
00024                 if (w->expires <= act_time) {
00025                         LOG(L_DBG, "Expired watcher %.*s\n", w->uri.len, w->uri.s);
00026                         w->expires = 0;
00027                         set_watcher_terminated_status(w);
00028                         _p->flags |= PFLAG_WATCHERINFO_CHANGED;
00029                         w->flags |= WFLAG_SUBSCRIPTION_CHANGED;
00030                         if (changed) *changed = 1;
00031                 }
00032 
00033                 /* send NOTIFY if needed */
00034                 notify = 0;
00035                 if ((w->flags & WFLAG_SUBSCRIPTION_CHANGED)) {
00036                         notify = 1;
00037                         if (changed) *changed = 1; /* ??? */
00038                 }
00039                 if (presentity_changed && is_watcher_authorized(w)) notify = 1;
00040                 if (notify) send_notify(_p, w);
00041                 w->flags &= ~WFLAG_SUBSCRIPTION_CHANGED;
00042                 
00043                 if (is_watcher_terminated(w)) {
00044                         next = w->next;
00045                         remove_watcher(_p, w);
00046                         free_watcher(w);
00047                         w = next;
00048                         if (changed) *changed = 1;
00049                 }
00050                 else w = w->next;
00051         }
00052 }
00053 
00054 static void process_winfo_watchers(presentity_t* _p, int *changed)
00055 {
00056         watcher_t *next, *w;
00057         int notify;
00058         
00059         /* !!! "changed" is not initialized here it is only set if change
00060          * in presentity occurs */
00061         
00062         w = _p->first_winfo_watcher;
00063         while (w) {
00064                 /* changes status of expired watcher */
00065                 if (w->expires <= act_time) {
00066                         LOG(L_DBG, "Expired watcher %.*s\n", w->uri.len, w->uri.s);
00067                         w->expires = 0;
00068                         set_watcher_terminated_status(w);
00069                         w->flags |= WFLAG_SUBSCRIPTION_CHANGED;
00070                         if (changed) *changed = 1;
00071                 }
00072 
00073                 /* send NOTIFY if needed */
00074                 notify = 0;
00075                 if ((w->flags & WFLAG_SUBSCRIPTION_CHANGED)) {
00076                         notify = 1;
00077                         if (changed) *changed = 1; /* ??? */
00078                 }
00079                 if ((_p->flags & PFLAG_WATCHERINFO_CHANGED) && 
00080                         is_watcher_authorized(w)) notify = 1;
00081                 if (notify) send_notify(_p, w);
00082                 w->flags &= ~WFLAG_SUBSCRIPTION_CHANGED;
00083                 
00084                 if (is_watcher_terminated(w)) {
00085                         next = w->next;
00086                         remove_watcher(_p, w);
00087                         free_watcher(w);
00088                         w = next;
00089                         if (changed) *changed = 1;
00090                 }
00091                 else w = w->next;
00092         }
00093 }
00094 
00095 /* static void mark_expired_tuples(presentity_t *_p, int *changed)
00096 {
00097         presence_tuple_t *t;
00098 
00099         t = _p->tuples;
00100         while (t) {     
00101                 if (t->expires < act_time) {
00102                         t->state = PS_OFFLINE;
00103                         if (changed) *changed = 1;
00104                         _p->flags |= PFLAG_PRESENCE_CHANGED;
00105                 }
00106                 t = t->next;
00107         }
00108 }*/
00109 
00110 static void remove_expired_tuples(presentity_t *_p, int *changed)
00111 {
00112         presence_tuple_t *t, *n;
00113 
00114         t = (presence_tuple_t*)_p->data.first_tuple;
00115         while (t) {
00116                 n = (presence_tuple_t *)t->data.next;
00117                 if (t->expires < act_time) {
00118                         DBG("Expiring tuple %.*s\n", t->data.contact.len, t->data.contact.s);
00119                         remove_presence_tuple(_p, t);
00120                         free_presence_tuple(t);
00121                         if (changed) *changed = 1;
00122                         _p->flags |= PFLAG_PRESENCE_CHANGED;
00123                 }
00124                 t = n;
00125         }
00126 }
00127 
00128 static void remove_expired_notes(presentity_t *_p)
00129 {
00130         pa_presence_note_t *n, *nn;
00131 
00132         n = (pa_presence_note_t*)_p->data.first_note;
00133         while (n) {
00134                 nn = (pa_presence_note_t *)n->data.next;
00135                 if (n->expires < act_time) {
00136                         DBG("Expiring note %.*s\n", FMT_STR(n->data.value));
00137                         remove_pres_note(_p, n);
00138                         _p->flags |= PFLAG_PRESENCE_CHANGED;
00139                 }
00140                 n = nn;
00141         }
00142 }
00143 
00144 static void remove_expired_extension_elements(presentity_t *_p)
00145 {
00146         pa_extension_element_t *n, *nn;
00147 
00148         n = (pa_extension_element_t *)_p->data.first_unknown_element;
00149         while (n) {
00150                 nn = (pa_extension_element_t *)n->data.next;
00151                 if (n->expires < act_time) {
00152                         DBG("Expiring person element %.*s\n", FMT_STR(n->dbid));
00153                         remove_extension_element(_p, n);
00154                         _p->flags |= PFLAG_PRESENCE_CHANGED;
00155                 }
00156                 n = nn;
00157         }
00158 }
00159 
00160 static inline int refresh_auth_rules(presentity_t *p)
00161 {
00162         /* TODO reload authorization rules if needed */
00163         if ((p->auth_rules_refresh_time > 0) && 
00164                         (p->auth_rules_refresh_time <= act_time)) {
00165 /*              INFO("refreshing auth rules\n"); */
00166                 ask_auth_rules(p); /* it will run next time if fails now */
00167                 p->auth_rules_refresh_time = act_time + auth_rules_refresh_time;
00168         }
00169         return 0;
00170 }
00171 
00172 static void process_tuple_change(presentity_t *p, tuple_change_info_t *info)
00173 {
00174         presence_tuple_t *tuple = NULL;
00175         basic_tuple_status_t orig;
00176         time_t e;
00177 
00178         DBG("processing tuple change message: %.*s, %.*s, %d\n",
00179                         FMT_STR(info->user), FMT_STR(info->contact), info->state);
00180 
00181         if (is_str_empty(&info->contact)) {
00182                 /* error - registered tuples need contact address */
00183                 ERR("invalid registered tuple (empty contact)\n");
00184                 return;
00185         }
00186         
00187         if (info->state == presence_tuple_closed) {
00188                 e = act_time + 2 * timer_interval;
00189         }
00190         else {
00191                 e = INT_MAX; /* act_time + default_expires; */
00192                 /* hack - re-registrations don't call the callback */
00193         }
00194         
00195         /* Find only registered (not published) tuple - don't overwrite
00196          * published information! */
00197         if (find_registered_presence_tuple(&info->contact, p, &tuple) != 0) {
00198                 /* not found -> create new tuple */
00199                 new_presence_tuple(&info->contact, e, &tuple, 0, NULL, NULL, NULL);
00200                 if (!tuple) return; /* error */
00201                 
00202                 tuple->data.status.basic = info->state;
00203                 add_presence_tuple(p, tuple);
00204                 p->flags |= PFLAG_PRESENCE_CHANGED;
00205         }
00206         else {
00207                 /* tuple found -> update */
00208                 orig = tuple->data.status.basic;
00209                 tuple->data.status.basic = info->state;
00210                 tuple->expires = e;
00211                 db_update_presence_tuple(p, tuple, 0);
00212                         
00213                 if (orig != tuple->data.status.basic) p->flags |= PFLAG_PRESENCE_CHANGED;
00214         }
00215 }
00216 
00217 static int process_qsa_message(presentity_t *p, client_notify_info_t *info)
00218 {
00219         TRACE("received QSA notification for presentity %.*s\n", FMT_STR(p->data.uri));
00220 
00221         /* TODO: handle it as publish for special tuple (but handle merging 
00222          * from multiple QSA sources in any way) */
00223         
00224         return 0;
00225 }
00226 
00227 static void process_presentity_messages(presentity_t *p)
00228 {
00229         mq_message_t *msg;
00230         tuple_change_info_t *info;
00231         client_notify_info_t *qsa_info;
00232 
00233         while ((msg = pop_message(&p->mq)) != NULL) {
00234 
00235                 /* FIXME: ugly data type detection */
00236                 if (msg->destroy_function == (destroy_function_f)free_tuple_change_info_content) {
00237                         info = (tuple_change_info_t*)get_message_data(msg);
00238                         if (info) process_tuple_change(p, info);
00239                 }
00240                 else {
00241                         /* QSA message */
00242                         qsa_info = (client_notify_info_t *)get_message_data(msg);
00243                         if (qsa_info) process_qsa_message(p, qsa_info);
00244                 }
00245                         
00246                 free_message(msg);
00247         }
00248 }
00249 
00250 
00251 int timer_presentity(presentity_t* _p)
00252 {
00253         int old_flags;
00254         int presentity_changed;
00255 
00256         PROF_START(pa_timer_presentity)
00257         old_flags = _p->flags;
00258 
00259         /* reload authorization rules if needed */
00260         refresh_auth_rules(_p);
00261         
00262         process_presentity_messages(_p);
00263         
00264         remove_expired_tuples(_p, NULL);
00265         
00266         remove_expired_notes(_p);
00267         remove_expired_extension_elements(_p);
00268         
00269         /* notify watchers and remove expired */
00270         process_watchers(_p, NULL);     
00271         /* notify winfo watchers and remove expired */
00272         process_winfo_watchers(_p, NULL); 
00273         
00274         /* notify internal watchers */
00275         presentity_changed = _p->flags & PFLAG_PRESENCE_CHANGED;
00276         if (presentity_changed) {
00277                 /* DBG("presentity %.*s changed\n", _p->uri.len, _p->uri.s); */
00278                 notify_qsa_watchers(_p);
00279         }
00280 
00281         /* clear presentity "change" flags */
00282         _p->flags &= ~(PFLAG_PRESENCE_CHANGED | PFLAG_WATCHERINFO_CHANGED);
00283         
00284         /* update DB record if something changed - USELESS */
00285 /*      if (changed) {
00286                 db_update_presentity(_p);
00287         } 
00288 */      
00289         PROF_STOP(pa_timer_presentity)
00290         return 0;
00291 }