http://qs1969.pair.com?node_id=738740

Update: Added some things, removed some things, the new version is a reply to this node.

Well, I was very excited when I learned that Pidgin accepts plugins written in Perl. (This is my 3rd plugin, the first two being far from complete.) I was not so excited to learn that the best documentation they have is for C (which I do not know). That being said, if there are better ways to do something, please let me know.

I tried to keep the lines to 80 columns (which, before previewing, I thought PM used to keep code tags from being too long. I now realize that the limit is less than 80 characters.)~

# English 2 13375p34k # TODO (in order of importance) # Convert &amp; (and such) to & (and such). # Set up preferences to allow user customization of the substitutio +ns use warnings; use strict; use Purple; use Acme::LeetSpeak; # Who says Acme should not be used in production +:P our %PLUGIN_INFO = ( perl_api_version => 2, name => "eng21337", version => "0.1.3", summary => "Anything you type (that is in <leet></leet> tags) will + betranslated to leetspeak and then sent.", description => "Anything you type (that is in <leet></leet> tags) +will be translated to leetspeak and then sent. I use the Acme::LeetSp +eak module (which does all the work :)). Please note that Pidgin conv +erts '&' to '&amp' so the leetspeak of 'me&you' will be 'm3&4Mpjo0' ( +or something). I'll fix it in a later version ;)", author => "Marc Green", url => "http://pidgin.im", load => "plugin_load", unload => "plugin_unload", ); my $pathname = '/plugins/core/eng21337'; my $catchloop = 0; # Used to stop infinite loop below (there is probab +ly a way # to avoid the whole thing but this works for now : +P) sub plugin_init { return %PLUGIN_INFO; } sub plugin_load { my $plugin = shift; # Everytime I send an im, call the subroutine sending_im_msg_cb my $convs_handle = Purple::Conversations::get_handle(); Purple::Signal::connect($convs_handle, "sending-im-msg", $plugin, \&sending_im_msg_cb, ''); Purple::Debug::info("eng21337", "plugin_load() - eng21137 plugin l +oaded\n"); } sub plugin_unload { Purple::Debug::info("eng21337", "plugin_load() - eng21137 plugin l +oaded\n"); } sub sending_im_msg_cb { my ($account, $who, $msg) = @_; $catchloop++; # Everytime I send() something from this subroutine (sending_im_ms +g_cb) # this subroutine gets called again (because I am send()ing someth +ing) # leading to an infinite loop. This is why I use $catchloop. I set + it to 0 # earlier so when this sub is called it will increase to 1 letting + the # below if statement execute. It is then set to 0 to restart the p +rocess. # This stops the infinite loop because once I call $im->send($msg) +, this # sub gets called again making $catchloop 2 which bypasses the if +statement # including the send(). Trust me, I've done the math. if ($catchloop == 1) { my $reg = qr{ &lt;leet&gt; # <leet> -- Pidgin converts <> + to html (.+?) # Stuff to be leet'd &lt;/leet&gt; # </leet> }x; $msg =~ s/$reg/leet($1);/ge if $msg =~ /$reg/; # Not sure how else to get the correct im handle besides these + 5 lines my $im; my @convs = Purple::get_conversations(); foreach my $conv (@convs) { $im = $conv->get_im_data() and last if $conv->get_name eq +$who; } $im->send($msg); # Show *both* users the leetspeak'd message $_[2] = ''; # Prevent double messages } $catchloop--; }

Put it in your ~/.purple/plugins folder (create if necessary), restart Pidgin, and enable it through Tools->Plugins.

Oh, and, to use it, just put any text you want turned into leetspeak between <leet></leet> tags.

Thanks to jdporter for the <leet></leet> tags suggestion. Thanks to the author of Acme::LeetSpeak for obvious reasons. (Make sure to download that module, by the way.)

Also, plans for eng2LOLCAT have been made: .oO( I think 3 or 4 substitutions and a download of Acme::LOLCAT will be all that is needed :P )

And you didn't even know bears could type.

Replies are listed 'Best First'.
Re: eng21337 -- A Pidgin plugin
by atcroft (Abbot) on Jan 25, 2009 at 09:58 UTC

    Interesting post. Regarding your first TODO note, HTML::Entities's decode_entities() function (or, perhaps, the two-element _decode_entities() function) look like a possible solution for you. The decode_entities() function would replace any entity; the two-element _decode_entities() function allows you to specify which entities should be decoded.

    HTH.

      Interesting post.

      .oO( Interesting does not necessarily mean good :P )

      Thank you for the suggestion -- I just try to keep the number of used modules to a minimum to save the user the hassle of installing them.

      And you didn't even know bears could type.

        In this case, "interesting" was that I was just looking a week or two ago at the plugin system, but didn't have time for more than a cursory look, so this gave me something I can experiment from (when I again have some free time).

        As to your trying to keep modules to a minimum, I can understand that, but I think this would give you more flexibility for later, if you decide you want to decode more than just &amp; . Just my humble opinion, though, and I'm open to there being other considerations I may be missing. If nothing else, it might be worth a look at "borrowing" the appropriate code, as an option.

        HTH (and good post).

Re: eng21337 -- A Pidgin plugin
by Lawliet (Curate) on Jan 25, 2009 at 21:40 UTC

    I added some preferences. One can now specify their own tag to be used (instead of being forced to use <leet></leet>, you can now use <LOLOLOL></LOLOLOL>, or whatever.) Also, I added an option to be in "Full Leet" mode. Enabling this option translates everything the user types to leet. That's right, everything -- no <leet></leet> tags required! In fact, if you put the <leet></leet> tags there, they will be turned into leetspeak (but Pidgin encodes the less than and greater than signs so it looks dumb)! Are you ready to unleash the fury? Oh, I also changed the wording of some things and such.

    The full plugin is below.

    # English 2 13375p34k # TODO (in order of importance) # Convert &amp; (and such) to & (and such). # Set up preferences to allow user customization of the substitutio +ns use warnings; use strict; use Purple; use Acme::LeetSpeak; # Who says Acme should not be used in production +:P our %PLUGIN_INFO = ( perl_api_version => 2, name => "eng21337", version => "0.2.1", summary => "Translate what you type to leetspeak.", description => "Anything you type (that is (optionally) between <l +eet></leet> tags (the tags are customizable, though)) will be transla +ted to leetspeak and then sent. I use the Acme::LeetSpeak module (whi +ch does all the work :)). Please note that Pidgin converts '&' to '&a +mp' so the leetspeak of 'me&you' will be 'm3&4Mpjo0' (or something). +I'll fix it in a later version ;)", author => "Marc Green", url => "http://pidgin.im", load => "plugin_load", unload => "plugin_unload", prefs_info => "prefs_info_cb", ); my $pathname = '/plugins/core/eng21337'; my $catchloop = 0; # Used to stop infinite loop below (there is probab +ly a way # to avoid the whole thing but this works for now : +P) sub plugin_init { return %PLUGIN_INFO; } sub plugin_load { my $plugin = shift; Purple::Prefs::add_none($pathname); Purple::Prefs::add_string("$pathname/leet_tag", "leet"); Purple::Prefs::add_bool("$pathname/full_leet", 1); # Everytime I send an im, call the subroutine sending_im_msg_cb my $convs_handle = Purple::Conversations::get_handle(); Purple::Signal::connect($convs_handle, "sending-im-msg", $plugin, \&sending_im_msg_cb, ''); Purple::Debug::info("eng21337", "plugin_load() - eng21137 plugin l +oaded\n"); } sub plugin_unload { Purple::Debug::info("eng21337", "plugin_load() - eng21137 plugin l +oaded\n"); } sub prefs_info_cb { my ($frame, $ppref); $frame = Purple::PluginPref::Frame->new(); $ppref = Purple::PluginPref->new_with_name_and_label("$pathname/le +et_tag", "Tag used to denote what should be turned into leetspeak.\n(E. +g., type 'dood' if you want to use <dood></dood>."); $ppref->set_type(2); $ppref->set_max_length(9); $frame->add($ppref); $ppref = Purple::PluginPref->new_with_name_and_label("$pathname/fu +ll_leet", "Always in leetspeak mode. (I.e., no <leet></leet> tags\nneede +d -- everything you type will be translated.)"); $frame->add($ppref); return $frame; } sub sending_im_msg_cb { my ($account, $who, $msg) = @_; my $leet_tag = quotemeta Purple::Prefs::get_string("$pathname/leet +_tag"); my $full_leet = Purple::Prefs::get_bool("$pathname/full_leet"); $catchloop++; # Everytime I send() something from this subroutine (sending_im_ms +g_cb) # this subroutine gets called again (because I am send()ing someth +ing) # leading to an infinite loop. This is why I use $catchloop. I set + it to 0 # earlier so when this sub is called it will increase to 1 letting + the # below if statement execute. It is then set to 0 to restart the p +rocess. # This stops the infinite loop because once I call $im->send($msg) +, this # sub gets called again making $catchloop 2 which bypasses the if +statement # including the send(). Trust me, I've done the math. if ($catchloop == 1) { # If the user wants everything translated to leetspeak, do so. # Else, just translate stuff between the tags if ($full_leet) { $msg = leet($msg); } else { my $reg = qr{ &lt;$leet_tag&gt; # <leet> (.+?) # Stuff to be leet'd &lt;/$leet_tag&gt; # </leet> }x; $msg =~ s/$reg/leet($1);/ge if $msg =~ /$reg/; } # Not sure how else to get the correct im handle besides these + 5 lines my $im; my @convs = Purple::get_conversations(); foreach my $conv (@convs) { $im = $conv->get_im_data() and last if $conv->get_name eq +$who; } $im->send($msg); # Show *both* users the leetspeak'd message $_[2] = ''; # Prevent double messages } $catchloop--; }

    It seems, when viewing the code from the download button, the formatting is not what I had intended it to be. I think I mixed spaces and tabs :O -- sorry about that.

    And you didn't even know bears could type.