📄 mod_filter.c
字号:
/* -------------------------------------------------------------------------- * * License * * The contents of this file are subject to the Jabber Open Source License * Version 1.0 (the "JOSL"). You may not copy or use this file, in either * source code or executable form, except in compliance with the JOSL. You * may obtain a copy of the JOSL at http://www.jabber.org/ or at * http://www.opensource.org/. * * Software distributed under the JOSL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL * for the specific language governing rights and limitations under the * JOSL. * * Copyrights * * Portions created by or assigned to Jabber.com, Inc. are * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact * information for Jabber.com, Inc. is available at http://www.jabber.com/. * * Portions Copyright (c) 1998-1999 Jeremie Miller. * * Acknowledgements * * Special thanks to the Jabber Open Source Contributors for their * suggestions and support of Jabber. * * Alternatively, the contents of this file may be used under the terms of the * GNU General Public License Version 2 or later (the "GPL"), in which case * the provisions of the GPL are applicable instead of those above. If you * wish to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the JOSL, * indicate your decision by deleting the provisions above and replace them * with the notice and other provisions required by the GPL. If you do not * delete the provisions above, a recipient may use your version of this file * under either the JOSL or the GPL. * * * --------------------------------------------------------------------------*/#include "jsm.h"/** * @file mod_filter.c * @brief This module handles the undocumented namespace jabber:iq:filter. The module is DEPRECATED, it may generate endless looping message bounces. * It also handles what mod_offline.c does as it needs to filter offline storage. * * it's alive! it now handles all functions that used to be handled by mod_offline.c * * mod_filter supports the following conditions: * - unavailable - matches when you aren't online * - from - matches if the sender is the same as the cdata in the <from/> tag * - resource - matches YOUR resource * - subject - matches the subject of the message * - body - matches the body of the message * - show - matches your <show/> in presence * - type - matches the type='' attrib * * and the following Actions: * - offline - stores the message offline * - forward - forwards the message to another jid * - reply - sends back an auto-reply message to the sender * - continue - continues processing of other rules * - settype - change the incoming message type * * you may specify any number of conditions/actions, if there are more than one condition, * ALL conditions must match for the rule to match, and ALL the listed actions will be taken. * * rules are checked in order, stopping when a match is found, unless a <continue/> flag is in place * * example rule: * <rule> * <unavailable/> * <offline/> * <reply>I'm not available right now</reply> * <forward>tsbandit@jabber.org</forward> * </rule> * * @note mod_filter must go first in module ordering * * * basic principle of mod_filter: * - each user has their own filter * - each filter contains zero or more rules * - each rule contains one or more conditions and one or more actions * - some conditions/actions may contain text to limit it further * - first matching condition is applied and processing quits (unless an action is continue) * - processed in order from client * - NO ACTION IMPLIES DROP * - FUTURE CONDITIONS: type, time, size * - FUTURE ACTIONS: edit,error,settype *//** default maximum ruleset size, can be overwritten by configuration */#define MOD_FILTER_MAX_SIZE 100/** * structure that contains a parsed action */typedef struct action_struct { pool p; /**< memory pool */ int is_match; /**< if the action is matched */ int has_action; /**< if there is an action at all */ int offline; /**< store offline */ int reply; /**< send an automated reply */ int settype; /**< set the type for a stanza */ int cont; /**< continue processing */ int error; /**< send an error reply */ jid forward; /**< forwarding destination *//* mapi m; */} _action, *action;/** * get the user's filter rules * * @param u the user * @return the filter rules */xmlnode mod_filter_get(udata u) { xmlnode ret; /* get the existing rules */ ret = xdb_get(u->si->xc, u->id, NS_FILTER); if(ret == NULL) { ret = xmlnode_new_tag("query"); xmlnode_put_attrib(ret, "xmlns", NS_FILTER); } return ret;}/** * store a message offline * * @param m the mapi_struct containing the message * @param rule the rule that configures if the message should be stored offline */void mod_filter_action_offline(mapi m, xmlnode rule) { xmlnode cur; /* look for event messages */ for(cur = xmlnode_get_firstchild(m->packet->x); cur != NULL; cur = xmlnode_get_nextsibling(cur)) { if(NSCHECK(cur, NS_EVENT)) { if(xmlnode_get_tag(cur, "id") != NULL) return; /* bah, we don't want to store events offline (XXX: do we?) */ if(xmlnode_get_tag(cur, "offline") != NULL) break; /* cur remaining set is the flag */ } } log_debug2(ZONE, LOGT_DELIVER|LOGT_STORAGE, "storing message for %s offline.",m->user->user); jutil_delay(m->packet->x,"Offline Storage"); if(xdb_act(m->si->xc, m->user->id, NS_OFFLINE, "insert", NULL, m->packet->x)) return; if(cur != NULL) { /* if there was an offline event to be sent, send it for gosh sakes! */ xmlnode cur2; jutil_tofrom(m->packet->x); /* erease everything else in the message */ for(cur2 = xmlnode_get_firstchild(m->packet->x); cur2 != NULL; cur2 = xmlnode_get_nextsibling(cur2)) if(cur2 != cur) xmlnode_hide(cur2); /* erase any other events */ for(cur2 = xmlnode_get_firstchild(cur); cur2 != NULL; cur2 = xmlnode_get_nextsibling(cur2)) xmlnode_hide(cur2); /* fill it in and send it on */ xmlnode_insert_tag(cur,"offline"); xmlnode_insert_cdata(xmlnode_insert_tag(cur,"id"),xmlnode_get_attrib(m->packet->x,"id"), -1); js_deliver(m->si, jpacket_reset(m->packet)); }}/** * send a reply message * * @param m the mapi_struct containing the stanza * @param rule the rule containing the instruction */void mod_filter_action_reply(mapi m,xmlnode rule) { char *reply=xmlnode_get_tag_data(rule,"reply"); xmlnode x = xmlnode_get_tag(m->packet->x, "x?xmlns=jabber:x:envelope"); int has_envelope = 0; /* check for infinite loops */ if(x != NULL) { xmlnode cur = xmlnode_get_tag(x, "forwardedby"); has_envelope = 1; for(; cur != NULL; cur = xmlnode_get_nextsibling(cur)) { if(xmlnode_get_type(cur) != NTYPE_TAG) continue; if(j_strcmp(xmlnode_get_name(cur), "forwardedby") == 0) { char *fb = xmlnode_get_attrib(cur, "jid"); jid j = jid_new(m->packet->p, fb); if(jid_cmpx(j, m->packet->to, JID_USER | JID_SERVER) == 0) { x = xmlnode_dup(m->packet->x); xmlnode_put_attrib(x, "to", jid_full(j)); xmlnode_put_attrib(x, "from", jid_full(m->packet->to)); deliver_fail(dpacket_new(x), "Replying would result in infinite loop"); return; } } } } if(!has_envelope) xmlnode_put_attrib(x = xmlnode_insert_tag(m->packet->x, "x"), "xmlns", "jabber:x:envelope"); xmlnode_put_attrib(xmlnode_insert_tag(x, "forwardedby"), "jid", jid_full(m->packet->to)); xmlnode_put_attrib(xmlnode_insert_tag(x, "from"), "jid", jid_full(m->packet->to)); xmlnode_put_attrib(xmlnode_insert_tag(x, "to"), "jid", jid_full(m->packet->from)); if(jid_cmpx(m->packet->to, m->packet->from, JID_USER | JID_SERVER) == 0) { /* special case, we sent a msg to ourselves */ /* try to find a session to deliver to... */ session s = js_session_get(m->user, m->packet->to->resource); s = s ? s : js_session_primary(m->user); s = s ? s : m->s; if(s == NULL) { /* can't find a deliverable session, store offline */ mod_filter_action_offline(m, rule); return; } /* just deliver to the session */ x = xmlnode_dup(m->packet->x); jutil_tofrom(x); if(xmlnode_get_tag(x, "body") != NULL) xmlnode_hide(xmlnode_get_tag(x, "body")); if(reply != NULL) xmlnode_insert_cdata(xmlnode_insert_tag(x, "body"), reply, -1); js_session_to(s, jpacket_new(x)); return; } x = xmlnode_dup(m->packet->x); jutil_tofrom(x); if(xmlnode_get_tag(x, "body") != NULL) xmlnode_hide(xmlnode_get_tag(x, "body")); if(reply != NULL) xmlnode_insert_cdata(xmlnode_insert_tag(x, "body"), reply, -1); deliver(dpacket_new(x),m->si->i);}/** * send an error reply to a stanza * * @param m the mapi_struct containing the incoming stanza * @param rule the rule containing the error command */void mod_filter_action_error(mapi m,xmlnode rule) { xmlnode err = xmlnode_get_tag(rule, "error"); log_debug2(ZONE, LOGT_DELIVER, "sending an error reply"); if(err != NULL) { xmlnode_insert_tag_node(m->packet->x, err); xmlnode_put_attrib(m->packet->x, "type", "error"); jpacket_reset(m->packet); } mod_filter_action_reply(m, rule);}/** * handle forwarding of a stanza * * @param m the mapi_struct containing the incoming stanza * @param rule the rule that configures the forwarding * @param j destination of the forwarded packet */void mod_filter_action_forward(mapi m,xmlnode rule,jid j) { int has_envelope=0; jid cur; xmlnode x=xmlnode_get_tag(m->packet->x,"x?xmlns=jabber:x:envelope"); /* check for infinite loops... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -