% -*- mode: slang; mode: fold -*- % % identity.sl - a macro for assuming various identities on a per-newsgroup % basis. % % Copyright (C) 2000-2003 Emmanuele Bassi % % This file may be redistributed and / or modified under the terms of the % GNU General Public License, version 2, as published by the Free Software % Foundation. % % $ Version: 2.8.0 - mar ott 26 14:17:12 CEST 2004 $ #iffalse % Documentation {{{ * Description: This macro allows the user to assign variable values, concerning his/hers identity, on a per-newsgroup basis: that is, to change some of the displayed informations depending on which newsgroup he/she is posting on a determined moment. * Installation and Usage: Make SLRN interpret this macro, with the usual line: interpret "identity.sl" inside your slrnrc file. The new identities are created by calling the new functions provided by this macro, such as: identity->add_new ("id", "newsgroup"); Where "id" it's a mnemonic ID representing the identity and "newsgroup" represents the newsgroup (or a regular expression matching more than one group) on which you want the Identity to be used in. This procedure creates a new Identity with the default values, taken from SLRN's resource file. If you have one or more identities you want to share across many groups, instead of creating a awkward regular expression (that, invariably, does not work properly), you may use the clone method: identity->clone ("old_id", "new_id"); This method clones an identity (marked by "old_id") into a new one (marked by "new_id"). Just remember to change the regular expression of the new identity with the set_regexp method (see below). To modify each detail of your identity, you have these functions: identity->set_from ("id", "username", "hostname"); identity->set_real ("id", "realname"); identity->set_replyto ("id", "reply-to"); identity->set_signature ("id", "/path/to/.signature"); identity->set_signoffstring ("id", "signoff_string"); identity->set_followupstring ("id", "followup_string"); identity->set_replystring ("id", "reply_string"); identity->set_customheaders ("id", "custom_headers"); identity->set_followupcustomheaders ("id", "followup_custom_headers"); identity->set_replycustomheaders ("id", "reply_custom_headers"); identity->set_regexp ("id", "regular_expression"); identity->set_saveto ("id", "save_to_file"); identity->set_description ("id", "Some descriptive text"); NOTE 1: All of these wrappers accept, as parameters, the ID of the identity you want to change and the parameter you want to be changed. The parameter has the same syntax used by SLRN, so use it as you'd write it in the SLRN resource file. NOTE 2: in the set_signature() procedure, you'll have to specify the entire path to the signature file; otherwise, SLRN will search the file in the current directory. NOTE 3: the set_regexp() method changes the regular expression for the identity: don't use it, unless you know what you are doing. It is also to be noted that the regexp uses the S-Lang regular expressions engine; this engine does not (yet) support some things (like an OR-like operator). NOTE 4: the set_saveto() method changes the location of the file where you want the articles saved, using the make_save_filename hook; the default is the SLRN default, that is the current group's name. If you have any other macro attached to this hook, there could be problems, since only one function is allowed to create the file name; if SLRN complains, and you don't want identity to fiddle with your other macro, simply comment out the last register_hook call. * Creating a new identity: Create a new macro file (e.g. "my_identities.sl"), and call the needed functions, for instance: % add a new identity for the Big8 news.* hierarchy identity->add_new ("news_big8", "^news\."); % change the signature when on news.* identity->set_signature ("news_big8", "/usr/local/signatures/sig-news"); Then save the file, and add the line: interpret "my_identities.sl" Inside your slrn-rc file. Remember to let SLRN interpret the identities file *after* the "identity.sl" macro file. * Viewing your identity: To view the Identity you are using on a group, use the "ESC I" escape sequence. +++ History: v2.8.0 revised the matching algorithm: if the user supplied a literal group name, skip the regexp match - otherwise, choose the last matching regular expression; this should protect group-specific identities against masking from hierarchy-specific identities. v2.7.0 added the "description" key, useful for defining a meaningful description of the identity. v2.6.2 reviewed documentation, corrected the bad RE of the example (thanks to Thomas Schultz); added the "saveto" variable: sets the file where you want the articles of a newsgroup saved. v2.6.1 reviewed documentation. v2.6.0 added the `clone' method, for duplicating an identity. v2.5.4 interpreting this macro before setting the related variables in the slrn-rc file now works (many thanks to Tomasz Sienicki); corrected the `Stack Underflow' error shown while entering in identity-less groups; more tighter checks on variables; v2.5.3 newline escaped in the view() method; v2.5.2 stronger check when registering hooks; v2.5.1 changed the hooks, so that posting from the groups pane also uses identity->assign(). v2.5.0 fixed a bug that occurred while entering in a newsgroup without an identity; v2.4.0 more variables: followup_string, reply_string, *custom_headers, signoff_string (thanks to Arkadiusz 'Jo Joro' Sochala); v2.3.0 more extensive identity informations showed in the popup window; v2.2.0 identities are now indexed by an id (thanks to J.B. Nicholson-Owens); v2.1.1 where possible, s/"error (sprintf"/verror; v2.1.0 some clean-ups; remove the nested foreach() in modify(); v2.0.0 added `hostname' and `username' to the list of mutable variables; added the set_*() wrappers to the create() and modify() methods; v1.1.0 added regexp matching for identities spanning more than one group; v1.0.0 initial release; #endif %}}} implements ("identity"); % Main identities variable %{{{ private variable Identity = Assoc_Type []; %}}} % Default values %{{{ private variable username_dfl = "", hostname_dfl = "", realname_dfl = "", replyto_dfl = "", signature_dfl = "", organization_dfl = "", signoffstring_dfl = "", customheaders_dfl = "", followupcustomheaders_dfl = "", replycustomheaders_dfl = "", replystring_dfl = "", followupstring_dfl = "", description_dfl = "Default"; %}}} % Current identity key %{{{ private variable Current_ID = ""; %}}} static define assign_default () %{{{ { set_string_variable ("username", username_dfl); set_string_variable ("hostname", hostname_dfl); set_string_variable ("signature", signature_dfl); set_string_variable ("realname", realname_dfl); set_string_variable ("replyto", replyto_dfl); set_string_variable ("organization", organization_dfl); set_string_variable ("signoff_string", signoffstring_dfl); set_string_variable ("followup_string", followupstring_dfl); set_string_variable ("custom_headers", customheaders_dfl); set_string_variable ("followup_custom_headers", followupcustomheaders_dfl); set_string_variable ("reply_custom_headers", replycustomheaders_dfl); set_string_variable ("reply_string", replystring_dfl); } %}}} static define retrieve_default () %{{{ { username_dfl = get_variable_value ("username"); hostname_dfl = get_variable_value ("hostname"); realname_dfl = get_variable_value ("realname"); replyto_dfl = get_variable_value ("replyto"); signature_dfl = get_variable_value ("signature"); organization_dfl = get_variable_value ("organization"); signoffstring_dfl = get_variable_value ("signoff_string"); customheaders_dfl = get_variable_value ("custom_headers"); followupcustomheaders_dfl = get_variable_value ("followup_custom_headers"); replycustomheaders_dfl = get_variable_value ("reply_custom_headers"); replystring_dfl = get_variable_value ("reply_string"); followupstring_dfl = get_variable_value ("followup_string"); } %}}} private define create (id) %{{{ { if (0 == strlen (id)) return; % Sanity check. if (assoc_key_exists (Identity, id)) { verror ("Identity: id %s already exists.", id); return; } % Add a new hash. Identity[id] = Assoc_Type []; % Save identity. Identity[id]["regx"] = "*"; Identity[id]["user"] = username_dfl; Identity[id]["host"] = hostname_dfl; Identity[id]["real"] = realname_dfl; Identity[id]["r_to"] = replyto_dfl; Identity[id]["sign"] = signature_dfl; Identity[id]["org"] = organization_dfl; Identity[id]["fol_s"] = followupstring_dfl; Identity[id]["rep_s"] = replystring_dfl; Identity[id]["cus_h"] = customheaders_dfl; Identity[id]["fol_ch"] = followupcustomheaders_dfl; Identity[id]["rep_ch"] = replycustomheaders_dfl; Identity[id]["sig_s"] = signoffstring_dfl; Identity[id]["save_to"] = ""; Identity[id]["desc"] = "New Identity"; } %}}} private define modify (id, key, value) %{{{ { !if (typeof (value) == String_Type) verror ("Identity: the value of %s must be a string", value); if ((0 == strlen (id)) or (0 == strlen (key))) return; if (assoc_key_exists (Identity, id)) if (assoc_key_exists (Identity[id], key)) Identity[id][key] = value; else verror ("Identity: key %s does not exists in %s", key, id); else verror ("Identity: an identity \`%s\' does not exists", id); } %}}} private define assign_val (var, key, default) %{{{ { % some sanity checks... % 1. Current_ID != ""; !if (strlen (Current_ID)) return; % 2. variable already set; if (0 == strcmp (get_variable_value (var), Identity[Current_ID][key])) return; % 3. no variable; !if (strlen (Identity[Current_ID][key])) { % 4. variable already set; !if (0 == strcmp (get_variable_value (var), default)) set_string_variable (var, default); return; } set_string_variable (var, Identity[Current_ID][key]); } %}}} % Wrappers {{{ static define add_new (id, news_re) %{{{ { if ((0 == strlen (id)) or (0 == strlen (news_re))) return; create (id); modify (id, "regx", news_re); } %}}} static define clone (old_id, new_id) %{{{ { !if ((typeof (old_id) == String_Type) and (typeof (new_id) == String_Type)) error ("Identity: invalid values in the clone method"); !if (assoc_key_exists (Identity, old_id)) verror ("Identity: id %s does not exist.", old_id); create (new_id); % expensive, but unavoidable. foreach (Identity[old_id]) using ("keys") { variable key = (); Identity[new_id][key] = Identity[old_id][key]; } } %}}} static define set_regexp (id, news_re) %{{{ { if (0 == strlen (id)) return; modify (id, "regx", news_re); } %}}} static define set_from (id, username, hostname) %{{{ { if (0 == strlen (id)) return; modify (id, "user", username); modify (id, "host", hostname); } %}}} static define set_signature (id, signature) %{{{ { if (0 == strlen (id)) return; modify (id, "sign", signature); } %}}} static define set_real (id, realname) %{{{ { if (0 == strlen (id)) return; modify (id, "real", realname); } %}}} static define set_replyto (id, reply_to) %{{{ { if (0 == strlen (id)) return; modify (id, "r_to", reply_to); } %}}} static define set_signoffstring (id, signoff_string) %{{{ { if (0 == strlen (id)) return; modify (id, "sig_s", signoff_string); } %}}} static define set_organization (id, organization) %{{{ { if (0 == strlen (id)) return; modify (id, "org", organization); } %}}} static define set_followupstring (id, followup_string) %{{{ { if (0 == strlen (id)) return; modify (id, "fol_s", followup_string); } %}}} static define set_replycustomheaders (id, reply_custom_headers) %{{{ { if (0 == strlen (id)) return; modify (id, "rep_ch", reply_custom_headers); } %}}} static define set_followupcustomheaders (id, followup_custom_headers) %{{{ { if (0 == strlen (id)) return; modify (id, "fol_ch", followup_custom_headers); } %}}} static define set_customheaders (id, custom_headers) %{{{ { if (0 == strlen (id)) return; modify (id, "cus_h", custom_headers); } %}}} static define set_replystring (id, reply_string) %{{{ { if (0 == strlen (id)) return; modify (id, "rep_s", reply_string); } %}}} static define set_saveto (id, save_location) %{{{ { if (0 == strlen (save_location)) return; modify (id, "save_to", save_location); } %}}} static define set_description (id, description) %{{{ { if (0 == strlen (description)) return; modify (id, "desc", description); } %}}} % }}} static define assign () %{{{ { variable newsgroup = current_newsgroup (); variable found = 0; if (0 == strlen (newsgroup)) return; foreach (Identity) using ("keys") { variable id = (); % fast-path: has the user specified a literal group name? if (0 == strcmp (newsgroup, Identity[id]["regx"])) { Current_ID = id; found = 1; break; } else if (0 != string_match (newsgroup, Identity[id]["regx"], 1)) { Current_ID = id; found = 1; } } if (1 == found) { % assign values. assign_val ("username", "user", username_dfl); assign_val ("hostname", "host", hostname_dfl); assign_val ("signature", "sign", signature_dfl); assign_val ("realname", "real", realname_dfl); assign_val ("replyto", "r_to", replyto_dfl); assign_val ("organization", "org", organization_dfl); assign_val ("signoff_string", "sig_s", signoffstring_dfl); assign_val ("followup_string", "fol_s", followupstring_dfl); assign_val ("custom_headers", "cus_h", customheaders_dfl); assign_val ("followup_custom_headers", "fol_ch", followupcustomheaders_dfl); assign_val ("reply_custom_headers", "rep_ch", replycustomheaders_dfl); assign_val ("reply_string", "rep_s", replystring_dfl); } else { % no identity found, set default values and reset the current ID. assign_default (); Current_ID = ""; } } %}}} static define save_file () %{{{ { if (("" != Current_ID) and (assoc_key_exists (Identity, Current_ID))) return Identity[Current_ID]["save_to"]; return current_newsgroup(); } %}}} static define view () %{{{ { variable id; if (is_group_mode ()) error (_function_name () + "does\'t work in group mode"); id = sprintf ("From: %s <%s@%s>\n" + "Reply-To: %s\n" + "Organization: %s\n" + "Signoff: %s\n" + "Signature: %s\n" + "F/up string: %s\n" + "Reply string: %s\n" + "Headers\n" + " Custom: %s\n" + " Followup: %s\n" + " Reply: %s" , get_variable_value ("realname"), get_variable_value ("username"), get_variable_value ("hostname"), get_variable_value ("replyto"), get_variable_value ("organization"), make_printable_string (get_variable_value ("signoff_string")), get_variable_value ("signature"), make_printable_string (get_variable_value ("followup_string")), make_printable_string (get_variable_value ("reply_string")), get_variable_value ("custom_headers"), get_variable_value ("followup_custom_headers"), get_variable_value ("reply_custom_headers")); if (("" != Current_ID) and (assoc_key_exists (Identity, Current_ID))) { id = sprintf ("%s\n" + "Current ID: %s ('%s')\n" + "Matching RE: %s\n" + "Save Location: %s" , id, Identity[Current_ID]["desc"], Current_ID, Identity[Current_ID]["regx"], Identity[Current_ID]["save_to"]); } popup_window (sprintf ("Identity on %s:", current_newsgroup ()), id); } %}}} % Default key assignment %{{{ definekey ("identity->view", "\eI", "article"); %}}} % Register hooks %{{{ !if (1 == register_hook ("startup_hook", "identity->retrieve_default")) error ("identity.sl: register_hook (startup_hook)"); !if (1 == register_hook ("article_mode_hook", "identity->assign")) error ("identity.sl: register hook (article_mode_hook)"); !if (1 == register_hook ("post_hook", "identity->assign")) error ("identity.sl: register_hook (post_hook)"); !if (1 == register_hook ("followup_hook", "identity->assign")) error ("identity.sl: register_hook (followup_hook)"); % Comment these two lines out, if you have another macro registered to the % make_save_filename hook. !if (1 == register_hook ("make_save_filename_hook", "identity->save_file")) error ("identity.sl: register_hook (make_save_filename_hook)"); %}}} % vim:tw=80 ts=8 noet