Events._pmod
Go to the documentation of this file.
1 /* Copyright (C) 2000-2006 Thomas Bopp, Thorsten Hampel, Ludger Merkens
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * $Id: Events.pmod,v 1.1 2008/03/31 13:39:57 exodusd Exp $
18  */
19 #include <events.h>
20 #include <config.h>
21 
22 
23 
24 
25 #ifdef EVENT_DEBUG
26 #define DEBUG_EVENT(s,args...) write(s+"\n",args)
27 #else
28 #define DEBUG_EVENT(s,args...)
29 #endif
30 
31 protected:
32  mapping event_desc = ([
33  EVENT_ENTER_INVENTORY: "enter-inventory",
34  EVENT_LEAVE_INVENTORY: "leave-inventory",
35  EVENT_UPLOAD: "upload",
36  EVENT_DOWNLOAD: "download",
37  EVENT_ATTRIBUTES_CHANGE: "attributes-change",
38  EVENT_MOVE: "move",
39  EVENT_SAY: "say",
40  EVENT_TELL: "tell",
41  EVENT_LOGIN: "login",
42  EVENT_LOGOUT: "logout",
43  EVENT_ATTRIBUTES_LOCK: "lock-attribute",
44  EVENT_EXECUTE: "execute",
45  EVENT_REGISTER_FACTORY: "register-factory",
46  EVENT_REGISTER_MODULE: "register-module",
47  EVENT_ATTRIBUTES_ACQUIRE: "acquire-attributes",
48  EVENT_ATTRIBUTES_QUERY: "query-attributes",
49  EVENT_REGISTER_ATTRIBUTE: "register-attribute",
50  EVENT_DELETE: "delete",
51  EVENT_ADD_MEMBER: "add-member",
52  EVENT_REMOVE_MEMBER: "remove-member",
53  EVENT_GRP_ADD_PERMISSION: "add-permissions-for-group",
54  EVENT_USER_CHANGE_PW: "user-change-password",
55  EVENT_SANCTION: "sanction",
56  EVENT_SANCTION_META: "meta-sanction",
57  EVENT_ARRANGE_OBJECT: "arrange-object",
58  EVENT_ANNOTATE: "annotate",
59  EVENT_LISTEN_EVENT: "listen-event",
60  EVENT_IGNORE_EVENT: "ignore-event",
61  EVENT_GET_INVENTORY: "get_inventory",
62  EVENT_DUPLICATE: "duplicate",
63  EVENT_REQ_SAVE: "save",
64  EVENT_GRP_ADDMUTUAL: "group-add-mutual",
65  EVENT_STATUS_CHANGED: "status-changed",
66  EVENT_SAVE_OBJECT: "save",
67  EVENT_REMOVE_ANNOTATION: "remove-annotation",
68  EVENT_DOWNLOAD_FINISHED: "download-finished",
69  EVENT_DB_REGISTER: "database-register",
70  EVENT_DB_UNREGISTER: "database-unregister",
71  EVENT_DB_QUERY: "database-query",
72  EVENT_SERVER_SHUTDOWN: "server-shutdown",
73  EVENT_CHANGE_QUOTA: "quota-change",
74  EVENT_REMOVE_ANNOTATION: "remove-annotation",
75  EVENT_DECORATE: "decorate",
76  EVENT_REMOVE_DECORATION: "remove-decoration",
77  ]);
78 
79 class Listener {
80 public:
81  int event_id;
82  object event_obj;
83  int event_phase;
84  function event_callback;
85  string callback_name;
86  object callback_obj;
87  object listening;
88  int objEvents;
89  string listener_id;
90 
91  void set(int eid, int phase, object obj, function callback, object|void l, void|int oEvents) {
92  if ( !objectp(obj) )
93  return;
94  if ( functionp(callback) ) {
95  callback_name = function_name(callback);
96  callback_obj = function_object(callback);
97  // need proxy
98  if ( objectp(callback_obj) && functionp(callback_obj->this))
99  }
100  event_id = eid;
101  event_phase = phase;
102  event_callback = callback;
103  listening = l;
104  objEvents = oEvents;
105  listener_id = sprintf("%x", hash((string)random(1000000) + time() + eid));
106  }
107 
108  string get_listener_id() {
109  return listener_id;
110  }
111 
112  void create(int eid, int phase, object obj,function callback,object|void l,void|int oEvents) {
113  set(eid, phase, obj, callback, l, oEvents);
114  }
115  void setObjectEvents()
116  {
117  objEvents = 1;
118  }
119 
120  int getObjectEvents()
121  {
122  return objEvents;
123  }
124  int get_event() {
125  return event_id;
126  }
127  object get_object() {
128  return event_obj;
129  }
130  int get_phase() {
131  return event_phase;
132  }
133  function get_callback() {
134  return event_callback;
135  }
136  object get_listening() {
137  return listening;
138  }
139 
140  string describe() {
141  return "Listener("+listener_id+","+
142  (objectp(event_obj)?event_obj->get_identifier():
143  "dead")+","+
144  (functionp(event_callback)?function_name(event_callback):"none")+
145  ", phase="+ (event_phase==PHASE_NOTIFY?"notify":"block")+","+
146  translate_eid(event_id)+")";
147  }
148 
149  string _sprintf() {
150  return describe();
151  }
152 
153  mixed `[] (mixed index) {
154  switch ( index ) {
155  case 0:
156  return event_callback;
157  case 1:
158  return event_id;
159  case 2:
160  return event_phase;
161  case 3:
162  return event_obj;
163  default:
164  return "unknown";
165  }
166  }
167  void notify(int eid, mixed args, object eventObj) {
168  if ( !functionp(event_callback) ) {
169  // event callback lost ?
170  if ( objectp(callback_obj) && callback_obj->status() >= 0 ) {
171  event_callback = callback_obj->find_function(callback_name);
172  }
173  }
174  if ( functionp(event_callback) ) {
175  if ( objEvents ) {
176  event_callback(eventObj);
177  }
178  else
179  event_callback(eid, @args);
180  }
181  }
182  int compare(object eobj, int eid, int ephase, function ecallback) {
183  if ( !functionp(ecallback) || !functionp(event_callback) )
184  return 0;
185  return event_obj == eobj && eid == event_id &&
186  ephase == event_phase && ecallback == event_callback;
187 
188  }
189 
190  mixed `==(object l) {
191  if ( !objectp(l) || !functionp(l->compare) )
192  return 0;
193  return l->compare(event_obj, event_id, event_phase, event_callback);
194  }
195  mixed `!=(object l) {
196  return !l->compare(event_obj, event_id, event_phase, event_callback);
197  }
198 }
199 
200 public:
201 
202 class Event {
203 public:
204  int event_id;
205  array listeners;
206  mixed params;
207 
208  void create(int id) {
209  event_id = id;
210  listeners = ({ });
211  }
212 
213  object add_listener(Listener l) {
214  // already got such a listener
215  if ( !objectp(l) )
216  return 0;
217 
218  foreach ( listeners, object listen ) {
219  if ( !objectp(listen) ) continue;
220  if ( listen == l ) {
221  return listen;
222  }
223  }
224  listeners += ({ l });
225  return l;
226  }
227 
228  void remove_listener(Listener l) {
229  listeners -= ({ l });
230  }
231 
232  array get_listeners() {
233  return listeners;
234  }
235 
236  void set_event(int id) {
237  event_id = id;
238  }
239 
240  int get_event() {
241  return event_id;
242  }
243 
244 protected:
245  void notify_listener(object l, mixed args) {
246  l->notify(event_id, args, this_object());
247  }
248 
249 public:
250 
251  void run_event(int phase, mixed args) {
252  listeners -= ({ 0 });
253  params = copy_value(args);
254  foreach( listeners, object l ) {
255  if ( objectp(l) && l->get_phase() == phase ) {
256  notify_listener(l, args);
257  }
258  }
259  }
260 
261  mapping get_params() {
262  return event_to_params(event_id, params);
263  }
264  mapping serialize_coal() {
265  return get_params();
266  }
267  string describe() {
268  return event_to_description(event_id, params);
269  }
270 
271  void remove_dead() {
272  foreach(listeners, object l) {
273  if ( !objectp(l) )
274  listeners -= ({ l });
275  }
276  }
277 
278  string _sprintf() {
279  int ilisten, idead;
280  foreach(listeners, object l) {
281  if ( !objectp(l) )
282  idead++;
283  else if ( functionp(l->get_callback) && !functionp(l->get_callback()) )
284  idead++;
285  else
286  ilisten++;
287  }
288 
289  return "Event("+event_id+","+translate_eid(event_id)+", "+
290  (event_id & EVENTS_MONITORED ? "monitored, ": "") +
291  ilisten+ " Listeners, "+idead+" dead)";
292  }
293 }
294 
295 
296 
297 /**
298  * Returns a string description for a given event.
299  *
300  * @param int eid - event id (bits)
301  * @return string description
302  */
303 string translate_eid(int eid)
304 {
305  array index = indices(event_desc);
306  eid = eid & EVENT_MASK;
307 
308  int events_second = eid & EVENTS_SECOND;
309  int events_module = eid & EVENTS_MODULES;
310  foreach(index, int id) {
311  if ( (id & eid) == (id | events_second | events_module) )
312  return event_desc[id];
313  }
314  return "unknown";
315 }
316 
317 /**
318  * Split a given integer bit array into segments. The EVENTS_MONITORED bit is
319  * preserved and set for each element of the resulting array.
320  *
321  * @param int event - the event to split
322  * @return array of single event-id-bits.
323  */
324 array split_events(int event)
325 {
326  // second events
327  int events_second = event & EVENTS_SECOND;
328 
329  array events = ({ });
330  int monitor = (event & EVENTS_MONITORED);
331 
332  for ( int i = 0; i <= 27; i++ ) {
333  if ( event & (1<<i) )
334  events += ({ (1<<i) | monitor | events_second });
335  }
336  return events;
337 }
338 
339 
340 mapping event_to_params(int event_id, array params)
341 {
342  int offset = 0;
343  mapping p = ([ ]);
344  if ( event_id & EVENTS_MONITORED ) {
345  p->context = params[0];
346  offset = 1;
347  }
348  p->object = params[offset+0];
349  p->eventID = event_id;
350  p->event = translate_eid(event_id);
351 
352  if ( event_id & EVENTS_MODULES ) {
353  p->object = params[offset+0];
354  if ( event_id & EVENT_DB_REGISTER )
355  p->key = params[offset+1];
356  if ( event_id & EVENT_DB_UNREGISTER )
357  p->key = params[offset+1];
358  }
359  else if ( event_id & EVENTS_SECOND ) {
360  p->object = params[offset+0];
361  if ( event_id & EVENT_GET_INVENTORY ) {
362  p->caller = params[offset+1];
363  }
364  else if ( event_id & EVENT_DUPLICATE ) {
365  p->caller = params[offset+1];
366  }
367  else if ( event_id & EVENT_GRP_ADDMUTUAL ) {
368  p->caller = params[offset+1];
369  p->group = params[offset+2];
370  }
371  else if ( event_id & EVENT_STATUS_CHANGED ) {
372  p->user = params[offset+1];
373  p->newFeatures = params[offset+2];
374  p->oldFeatures = params[offset+3];
375  }
376  else if ( event_id & EVENT_REMOVE_ANNOTATION ) {
377  p->caller = params[offset+1];
378  p->annotation = params[offset+2];
379  }
380  else if ( event_id & EVENT_DOWNLOAD_FINISHED ) {
381  p->caller = params[offset+1];
382  }
383  else if ( event_id & EVENT_LOCK ) {
384  }
385  else if ( event_id & EVENT_DECORATE ) {
386  p->caller = params[offset+1];
387  p->decoration = params[offset+2];
388  }
389  else if ( event_id & EVENT_REMOVE_DECORATION ) {
390  p->caller = params[offset+1];
391  p->decoration = params[offset+2];
392  }
393 
394  }
395  else if ( event_id & EVENT_ENTER_INVENTORY )
396  {
397  p->container = params[offset+0];
398  p->enteringObject = params[offset+1];
399  }
400  else if ( event_id & EVENT_LEAVE_INVENTORY )
401  {
402  p->container = params[offset+0];
403  p->leavingObject = params[offset+1];
404  }
405  else if ( event_id & EVENT_ATTRIBUTES_CHANGE ) {
406  p->caller = params[offset+1];
407  p->data = params[offset+2];
408  p->olddata = params[offset+3];
409  }
410  else if ( event_id & EVENT_REGISTER_ATTRIBUTE ) {
411  p->caller = params[offset+1];
412  p->data = params[offset+2]->get_key();
413  }
414  else if ( event_id & EVENT_ATTRIBUTES_ACQUIRE ) {
415  p->caller = params[offset+1];
416  p->data = params[offset+2];
417  }
418  else if ( event_id & EVENT_USER_CHANGE_PW ) {
419  p->caller = params[offset+1];
420  }
421  else if ( event_id & EVENT_ATTRIBUTES_LOCK ) {
422  p->caller = params[offset+1];
423  p->data = params[offset+2];
424  p->lock = params[offset+3];
425  }
426  else if ( event_id & EVENT_ARRANGE_OBJECT ) {
427  p->caller = params[offset+1];
428  p->data = params[offset+2];
429  }
430  else if ( event_id & EVENT_LISTEN_EVENT ) {
431  p->caller = params[offset+1];
432  p->event = params[offset+2];
433  p->phase = params[offset+3];
434  }
435  else if ( event_id & EVENT_IGNORE_EVENT ) {
436  p->caller = params[offset+1];
437  p->event = params[offset+2];
438  }
439  else if ( event_id & EVENT_UPLOAD ) {
440  p->size = params[offset+2];
441  p->user = params[offset+1];
442  }
443  else if ( event_id & EVENT_DOWNLOAD ) {
444  }
445  else if ( event_id & EVENT_MOVE ) {
446  p->movedByObject = params[offset+1];
447  p->fromContainer = params[offset+2];
448  p->toContainer = params[offset+3];
449  }
450  else if ( event_id & EVENT_SAY ) {
451  p->room = params[offset+0];
452  p->message = params[offset+2];
453  }
454  else if ( event_id & EVENT_TELL ) {
455  p->user = params[offset+0];
456  p->sender = params[offset+1];
457  p->message = params[offset+2];
458  }
459  else if ( event_id & EVENT_LOGIN ) {
460  p->user = params[offset+0];
461  p->newFeatures = params[offset+2];
462  p->oldFeatures = params[offset+3];
463  }
464  else if ( event_id & EVENT_LOGOUT ) {
465  p->socket = params[offset+2];
466  }
467  else if ( event_id & EVENT_EXECUTE ) {
468  p->caller = params[offset+1];
469  p->data = params[offset+2];
470  }
471  else if ( event_id & EVENT_DELETE ) {
472  p->caller = params[offset+1];
473  }
474  else if ( event_id & EVENT_ADD_MEMBER ) {
475  p->addObject = params[offset+2];
476  p->caller = params[offset+1];
477  }
478  else if ( event_id & EVENT_REMOVE_MEMBER ) {
479  p->removeObject = params[offset+2];
480  p->caller = params[offset+1];
481  }
482  else if ( event_id & EVENT_SANCTION ) {
483  p->caller = params[offset+1];
484  p->sanctionObject = params[offset+2];
485  p->permission = params[offset+3];
486  }
487  else if ( event_id & EVENT_SANCTION_META ) {
488  p->caller = params[offset+1];
489  p->sanctionObject = params[offset+2];
490  p->permission = params[offset+3];
491  }
492  else if ( event_id & EVENT_ANNOTATE ) {
493  p->caller = params[offset+1];
494  p->annotationObject = params[offset+2];
495  }
496  return p;
497 }
498 
499 string event_to_description(int event_id, array args)
500 {
501  if ( !arrayp(args) )
502  return "Event(" + event_id + ", never run)";
503 
504  mapping p = event_to_params(event_id, args);
505  string desc = timelib.event_time(time()) + " ";
506 
507  string objstr = (objectp(p->object) ? p->object->describe() : "null");
508  string callerstr = (objectp(p->caller) ?
509  (functionp(p->caller->describe) ? p->caller->describe() :
510  sprintf("Caller:%O", p->caller)) : "null");
511 
512 
513  if ( objectp(p->context) ) {
514  desc += sprintf("in %s(#%d) ",
515  p->context->get_identifier(),
516  p->context->get_object_id());
517  }
518  if ( event_id & EVENTS_MODULES ) {
519  if ( event_id & EVENT_DB_REGISTER ) {
520  desc += sprintf("%s DB REGISTER %O", objstr, p->key);
521  }
522  if ( event_id & EVENT_DB_UNREGISTER ) {
523  desc += sprintf("%s DB UNREGISTER %O", objstr, p->key);
524  }
525  }
526  else if ( event_id & EVENTS_SECOND ) {
527  if ( event_id & EVENT_GET_INVENTORY ) {
528  desc += sprintf("%s INVENTORY by %s",
529  objstr,
530  callerstr);
531  }
532  else if ( event_id & EVENT_DUPLICATE ) {
533  desc += sprintf("%s DUPLICATE by %s", objstr, callerstr);
534  }
535  else if ( event_id & EVENT_GRP_ADDMUTUAL ) {
536  desc += sprintf("%s ADD MUTUAL %s by %s",
537  objstr, p->group->describe(),
538  callerstr);
539  }
540  else if ( event_id & EVENT_STATUS_CHANGED ) {
541  desc += sprintf("%s STATUS CHANGED from %d to %d",
542  objstr, p->oldFeatures, p->newFeatures);
543  }
544  else if ( event_id & EVENT_REMOVE_ANNOTATION ) {
545  desc += sprintf("%s REMOVE ANNOTATION %s by %s",
546  objstr,
547  p->annotation->describe(),
548  callerstr);
549  }
550  else if ( event_id & EVENT_DOWNLOAD_FINISHED ) {
551  desc += sprintf("%s DOWNLOAD FINISHED by %s", objstr, callerstr);
552  }
553  else if ( event_id & EVENT_LOCK ) {
554  }
555  else {
556  desc += sprintf("UNKNOWN EVENT: %d %O", event_id, p);
557  desc = replace(desc, "\n", "");
558  }
559  }
560  else if ( event_id & EVENT_ENTER_INVENTORY )
561  {
562  desc += p->enteringObject->describe()+" enters " + objstr;
563  }
564  else if ( event_id & EVENT_LEAVE_INVENTORY )
565  {
566  desc += p->leavingObject->describe()+" leaves " + objstr;
567  }
568  else if ( event_id & EVENT_ATTRIBUTES_CHANGE ) {
569  string data = indices(p->data) * ",";
570  desc += sprintf("%s MODIFY %s by %s",
571  objstr,
572  data,
573  callerstr);
574  }
575  else if ( event_id & EVENT_ATTRIBUTES_LOCK ) {
576  desc += sprintf("%s %s %s by %s",
577  objstr,
578  (p->lock?"LOCK":"UNLOCK"),
579  p->data,
580  callerstr);
581  }
582  else if ( event_id & EVENT_REGISTER_ATTRIBUTE ) {
583  desc += sprintf("%s REGISTER %s by %s",
584  objstr,
585  p->data,
586  callerstr);
587  }
588  else if ( event_id & EVENT_ATTRIBUTES_ACQUIRE ) {
589  desc += sprintf("%s ACQUIRE %s by %s",
590  objstr,
591  p->data,
592  callerstr);
593  }
594  else if ( event_id & EVENT_USER_CHANGE_PW ) {
595  desc += sprintf("%s CHANGE PASSWORD by %s",
596  objstr,
597  callerstr);
598  }
599  else if ( event_id & EVENT_ARRANGE_OBJECT ) {
600  string data = values(p->data) * ",";
601  desc += sprintf("%s ARRANGE %s by %s",
602  objstr,
603  data,
604  callerstr);
605  }
606  else if ( event_id & EVENT_LISTEN_EVENT ) {
607  desc += sprintf("%s LISTEN %s %s by %s",
608  objstr,
609  translate_eid(p->event),
610  (p->event & EVENTS_MONITORED ? "monitored":""),
611  callerstr);
612  }
613  else if ( event_id & EVENT_IGNORE_EVENT ) {
614  desc += sprintf("%s IGNORE %s %s by %s",
615  objstr,
616  translate_eid(p->event),
617  (p->event & EVENTS_MONITORED ? "monitored":""),
618  callerstr);
619  }
620  else if ( event_id & EVENT_UPLOAD ) {
621  desc += sprintf("%s UPLOAD %s (%d bytes)",
622  objectp(p->user) ? (functionp(p->user->describe)?p->user->describe(): sprintf("%O", p->user)):"null",
623  objstr,
624  p->size);
625  }
626  else if ( event_id & EVENT_DOWNLOAD ) {
627  desc += sprintf("%s DOWNLOAD", objstr);
628  }
629  else if ( event_id & EVENT_MOVE ) {
630  desc += sprintf("%s MOVE %s from %s to %s",
631  objstr,
632  (objectp(p->movedByObject)?p->movedByObject->describe():"null"),
633  (objectp(p->fromContainer)?p->fromContainer->describe():"null"),
634  (objectp(p->toContainer)?p->toContainer->describe():"null"));
635  }
636  else if ( event_id & EVENT_SAY ) {
637  desc += sprintf("%s SAY %s in %s",
638  objstr,
639  p->message,
640  p->room->describe());
641  }
642  else if ( event_id & EVENT_TELL ) {
643  desc += sprintf("%s TELL by %s: %s",
644  p->user->describe(),
645  p->sender->describe(),
646  p->message);
647  }
648  else if ( event_id & EVENT_LOGIN ) {
649  desc += sprintf("%s LOGIN", p->user->describe());
650  }
651  else if ( event_id & EVENT_LOGOUT ) {
652  desc += sprintf("%s LOGOUT", objstr);
653  }
654  else if ( event_id & EVENT_EXECUTE ) {
655  string data = replace(sprintf("%O", p->data), "\n", " ");
656  desc += sprintf("%s EXECUTE by %s (%O)",
657  objstr,
658  callerstr,
659  data);
660  }
661  else if ( event_id & EVENT_DELETE ) {
662  desc += sprintf("%s DELETE %s",
663  objstr,
664  callerstr);
665  }
666  else if ( event_id & EVENT_ADD_MEMBER ) {
667  desc += sprintf("%s ADD MEMBER %s by %s",
668  objstr,
669  p->addObject->describe(),
670  callerstr);
671  }
672  else if ( event_id & EVENT_REMOVE_MEMBER ) {
673  desc += sprintf("%s REMOVE MEMBER %s by %s",
674  objstr,
675  p->removeObject->describe(),
676  callerstr);
677  }
678  else if ( event_id & EVENT_SANCTION ) {
679  desc += sprintf("%s SANCTION %s with %d by %s",
680  objstr,
681  p->sanctionObject->describe(),
682  p->permission,
683  callerstr);
684  }
685  else if ( event_id & EVENT_SANCTION_META ) {
686  desc += sprintf("%s SANCTION META %s with %d by %s",
687  objstr,
688  p->sanctionObject->describe(),
689  p->permission,
690  callerstr);
691  }
692  else if ( event_id & EVENT_ANNOTATE ) {
693  desc += sprintf("%s ANNOTATE with %s by %s",
694  objstr,
695  p->annotationObject->describe(),
696  callerstr);
697  }
698  else {
699  desc += sprintf("UNKNOWN EVENT: %d %O", event_id, p);
700  desc = replace(desc, "\n", "");
701 
702  }
703  return desc;
704 }
705 
706 
707 };