1 /* Copyright (C) 2000-2006 Thomas Bopp, Thorsten Hampel, Ludger Merkens
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.
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.
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
17 * $Id: Events.pmod,v 1.1 2008/03/31 13:39:57 exodusd Exp $
26 #define DEBUG_EVENT(s,args...) write(s+"\n",args)
28 #define DEBUG_EVENT(s,args...)
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",
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",
84 function event_callback;
91 void set(int eid, int phase, object obj, function callback, object|void l, void|int oEvents) {
94 if ( functionp(callback) ) {
95 callback_name = function_name(callback);
96 callback_obj = function_object(callback);
98 if ( objectp(callback_obj) && functionp(callback_obj->this))
102 event_callback = callback;
105 listener_id = sprintf("%x", hash((string)random(1000000) + time() + eid));
108 string get_listener_id() {
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);
115 void setObjectEvents()
120 int getObjectEvents()
127 object get_object() {
133 function get_callback() {
134 return event_callback;
136 object get_listening() {
141 return "Listener("+listener_id+","+
142 (objectp(event_obj)?event_obj->get_identifier():
144 (functionp(event_callback)?function_name(event_callback):"none")+
145 ", phase="+ (event_phase==PHASE_NOTIFY?"notify":"block")+","+
146 translate_eid(event_id)+")";
153 mixed `[] (mixed index) {
156 return event_callback;
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);
174 if ( functionp(event_callback) ) {
176 event_callback(eventObj);
179 event_callback(eid, @args);
182 int compare(object eobj, int eid, int ephase, function ecallback) {
183 if ( !functionp(ecallback) || !functionp(event_callback) )
185 return event_obj == eobj && eid == event_id &&
186 ephase == event_phase && ecallback == event_callback;
190 mixed `==(object l) {
191 if ( !objectp(l) || !functionp(l->compare) )
193 return l->compare(event_obj, event_id, event_phase, event_callback);
195 mixed `!=(object l) {
196 return !l->compare(event_obj, event_id, event_phase, event_callback);
208 void create(int id) {
213 object add_listener(Listener l) {
214 // already got such a listener
218 foreach ( listeners, object listen ) {
219 if ( !objectp(listen) ) continue;
224 listeners += ({ l });
228 void remove_listener(Listener l) {
229 listeners -= ({ l });
232 array get_listeners() {
236 void set_event(int id) {
245 void notify_listener(object l, mixed args) {
246 l->notify(event_id, args, this_object());
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);
261 mapping get_params() {
262 return event_to_params(event_id, params);
264 mapping serialize_coal() {
268 return event_to_description(event_id, params);
272 foreach(listeners, object l) {
274 listeners -= ({ l });
280 foreach(listeners, object l) {
283 else if ( functionp(l->get_callback) && !functionp(l->get_callback()) )
289 return "Event("+event_id+","+translate_eid(event_id)+", "+
290 (event_id & EVENTS_MONITORED ? "monitored, ": "") +
291 ilisten+ " Listeners, "+idead+" dead)";
298 * Returns a string description for a given event.
300 * @param int eid - event id (bits)
301 * @return string description
303 string translate_eid(int eid)
305 array index = indices(event_desc);
306 eid = eid & EVENT_MASK;
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];
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.
321 * @param int event - the event to split
322 * @return array of single event-id-bits.
324 array split_events(int event)
327 int events_second = event & EVENTS_SECOND;
329 array events = ({ });
330 int monitor = (event & EVENTS_MONITORED);
332 for ( int i = 0; i <= 27; i++ ) {
333 if ( event & (1<<i) )
334 events += ({ (1<<i) | monitor | events_second });
340 mapping event_to_params(int event_id, array params)
344 if ( event_id & EVENTS_MONITORED ) {
345 p->context = params[0];
348 p->object = params[offset+0];
349 p->eventID = event_id;
350 p->event = translate_eid(event_id);
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];
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];
364 else if ( event_id & EVENT_DUPLICATE ) {
365 p->caller = params[offset+1];
367 else if ( event_id & EVENT_GRP_ADDMUTUAL ) {
368 p->caller = params[offset+1];
369 p->group = params[offset+2];
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];
376 else if ( event_id & EVENT_REMOVE_ANNOTATION ) {
377 p->caller = params[offset+1];
378 p->annotation = params[offset+2];
380 else if ( event_id & EVENT_DOWNLOAD_FINISHED ) {
381 p->caller = params[offset+1];
383 else if ( event_id & EVENT_LOCK ) {
385 else if ( event_id & EVENT_DECORATE ) {
386 p->caller = params[offset+1];
387 p->decoration = params[offset+2];
389 else if ( event_id & EVENT_REMOVE_DECORATION ) {
390 p->caller = params[offset+1];
391 p->decoration = params[offset+2];
395 else if ( event_id & EVENT_ENTER_INVENTORY )
397 p->container = params[offset+0];
398 p->enteringObject = params[offset+1];
400 else if ( event_id & EVENT_LEAVE_INVENTORY )
402 p->container = params[offset+0];
403 p->leavingObject = params[offset+1];
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];
410 else if ( event_id & EVENT_REGISTER_ATTRIBUTE ) {
411 p->caller = params[offset+1];
412 p->data = params[offset+2]->get_key();
414 else if ( event_id & EVENT_ATTRIBUTES_ACQUIRE ) {
415 p->caller = params[offset+1];
416 p->data = params[offset+2];
418 else if ( event_id & EVENT_USER_CHANGE_PW ) {
419 p->caller = params[offset+1];
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];
426 else if ( event_id & EVENT_ARRANGE_OBJECT ) {
427 p->caller = params[offset+1];
428 p->data = params[offset+2];
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];
435 else if ( event_id & EVENT_IGNORE_EVENT ) {
436 p->caller = params[offset+1];
437 p->event = params[offset+2];
439 else if ( event_id & EVENT_UPLOAD ) {
440 p->size = params[offset+2];
441 p->user = params[offset+1];
443 else if ( event_id & EVENT_DOWNLOAD ) {
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];
450 else if ( event_id & EVENT_SAY ) {
451 p->room = params[offset+0];
452 p->message = params[offset+2];
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];
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];
464 else if ( event_id & EVENT_LOGOUT ) {
465 p->socket = params[offset+2];
467 else if ( event_id & EVENT_EXECUTE ) {
468 p->caller = params[offset+1];
469 p->data = params[offset+2];
471 else if ( event_id & EVENT_DELETE ) {
472 p->caller = params[offset+1];
474 else if ( event_id & EVENT_ADD_MEMBER ) {
475 p->addObject = params[offset+2];
476 p->caller = params[offset+1];
478 else if ( event_id & EVENT_REMOVE_MEMBER ) {
479 p->removeObject = params[offset+2];
480 p->caller = params[offset+1];
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];
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];
492 else if ( event_id & EVENT_ANNOTATE ) {
493 p->caller = params[offset+1];
494 p->annotationObject = params[offset+2];
499 string event_to_description(int event_id, array args)
502 return "Event(" + event_id + ", never run)";
504 mapping p = event_to_params(event_id, args);
505 string desc = timelib.event_time(time()) + " ";
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");
513 if ( objectp(p->context) ) {
514 desc += sprintf("in %s(#%d) ",
515 p->context->get_identifier(),
516 p->context->get_object_id());
518 if ( event_id & EVENTS_MODULES ) {
519 if ( event_id & EVENT_DB_REGISTER ) {
520 desc += sprintf("%s DB REGISTER %O", objstr, p->key);
522 if ( event_id & EVENT_DB_UNREGISTER ) {
523 desc += sprintf("%s DB UNREGISTER %O", objstr, p->key);
526 else if ( event_id & EVENTS_SECOND ) {
527 if ( event_id & EVENT_GET_INVENTORY ) {
528 desc += sprintf("%s INVENTORY by %s",
532 else if ( event_id & EVENT_DUPLICATE ) {
533 desc += sprintf("%s DUPLICATE by %s", objstr, callerstr);
535 else if ( event_id & EVENT_GRP_ADDMUTUAL ) {
536 desc += sprintf("%s ADD MUTUAL %s by %s",
537 objstr, p->group->describe(),
540 else if ( event_id & EVENT_STATUS_CHANGED ) {
541 desc += sprintf("%s STATUS CHANGED from %d to %d",
542 objstr, p->oldFeatures, p->newFeatures);
544 else if ( event_id & EVENT_REMOVE_ANNOTATION ) {
545 desc += sprintf("%s REMOVE ANNOTATION %s by %s",
547 p->annotation->describe(),
550 else if ( event_id & EVENT_DOWNLOAD_FINISHED ) {
551 desc += sprintf("%s DOWNLOAD FINISHED by %s", objstr, callerstr);
553 else if ( event_id & EVENT_LOCK ) {
556 desc += sprintf("UNKNOWN EVENT: %d %O", event_id, p);
557 desc = replace(desc, "\n", "");
560 else if ( event_id & EVENT_ENTER_INVENTORY )
562 desc += p->enteringObject->describe()+" enters " + objstr;
564 else if ( event_id & EVENT_LEAVE_INVENTORY )
566 desc += p->leavingObject->describe()+" leaves " + objstr;
568 else if ( event_id & EVENT_ATTRIBUTES_CHANGE ) {
569 string data = indices(p->data) * ",";
570 desc += sprintf("%s MODIFY %s by %s",
575 else if ( event_id & EVENT_ATTRIBUTES_LOCK ) {
576 desc += sprintf("%s %s %s by %s",
578 (p->lock?"LOCK":"UNLOCK"),
582 else if ( event_id & EVENT_REGISTER_ATTRIBUTE ) {
583 desc += sprintf("%s REGISTER %s by %s",
588 else if ( event_id & EVENT_ATTRIBUTES_ACQUIRE ) {
589 desc += sprintf("%s ACQUIRE %s by %s",
594 else if ( event_id & EVENT_USER_CHANGE_PW ) {
595 desc += sprintf("%s CHANGE PASSWORD by %s",
599 else if ( event_id & EVENT_ARRANGE_OBJECT ) {
600 string data = values(p->data) * ",";
601 desc += sprintf("%s ARRANGE %s by %s",
606 else if ( event_id & EVENT_LISTEN_EVENT ) {
607 desc += sprintf("%s LISTEN %s %s by %s",
609 translate_eid(p->event),
610 (p->event & EVENTS_MONITORED ? "monitored":""),
613 else if ( event_id & EVENT_IGNORE_EVENT ) {
614 desc += sprintf("%s IGNORE %s %s by %s",
616 translate_eid(p->event),
617 (p->event & EVENTS_MONITORED ? "monitored":""),
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",
626 else if ( event_id & EVENT_DOWNLOAD ) {
627 desc += sprintf("%s DOWNLOAD", objstr);
629 else if ( event_id & EVENT_MOVE ) {
630 desc += sprintf("%s MOVE %s from %s to %s",
632 (objectp(p->movedByObject)?p->movedByObject->describe():"null"),
633 (objectp(p->fromContainer)?p->fromContainer->describe():"null"),
634 (objectp(p->toContainer)?p->toContainer->describe():"null"));
636 else if ( event_id & EVENT_SAY ) {
637 desc += sprintf("%s SAY %s in %s",
640 p->room->describe());
642 else if ( event_id & EVENT_TELL ) {
643 desc += sprintf("%s TELL by %s: %s",
645 p->sender->describe(),
648 else if ( event_id & EVENT_LOGIN ) {
649 desc += sprintf("%s LOGIN", p->user->describe());
651 else if ( event_id & EVENT_LOGOUT ) {
652 desc += sprintf("%s LOGOUT", objstr);
654 else if ( event_id & EVENT_EXECUTE ) {
655 string data = replace(sprintf("%O", p->data), "\n", " ");
656 desc += sprintf("%s EXECUTE by %s (%O)",
661 else if ( event_id & EVENT_DELETE ) {
662 desc += sprintf("%s DELETE %s",
666 else if ( event_id & EVENT_ADD_MEMBER ) {
667 desc += sprintf("%s ADD MEMBER %s by %s",
669 p->addObject->describe(),
672 else if ( event_id & EVENT_REMOVE_MEMBER ) {
673 desc += sprintf("%s REMOVE MEMBER %s by %s",
675 p->removeObject->describe(),
678 else if ( event_id & EVENT_SANCTION ) {
679 desc += sprintf("%s SANCTION %s with %d by %s",
681 p->sanctionObject->describe(),
685 else if ( event_id & EVENT_SANCTION_META ) {
686 desc += sprintf("%s SANCTION META %s with %d by %s",
688 p->sanctionObject->describe(),
692 else if ( event_id & EVENT_ANNOTATE ) {
693 desc += sprintf("%s ANNOTATE with %s by %s",
695 p->annotationObject->describe(),
699 desc += sprintf("UNKNOWN EVENT: %d %O", event_id, p);
700 desc = replace(desc, "\n", "");