HexChat Perl get network context instead of channel context - perl

I have the following code in a channel message hook to get the server context and print to the server window:
my $network = HexChat::get_info('network');
my $networkContext = HexChat::find_context(undef, $network);
HexChat::set_context($networkContext);
HexChat::print('test');
It works if I already have the server window open, or a channel on a different server, but if the current window is a channel on the server I request the context for I get the context of the current channel instead of the server. Is there any way to force find_context to always get the server context so 'test' is printed in the server window instead of the current channel's window

Translate this snippet from one of my scripts to perl basically:
for chan in hexchat.get_list('channels'):
if chan.type == 1 and chan.id == hexchat.get_prefs('id'):
SERVER_CONTEXT = chan.context
find_context() goes off of strings which not very smart since they are not unique. Going of the unique id of the network is always correct and using the context type always gets the server tab (though note users can disable that).

Here is the perl I ended up using:
sub get_server_context() {
foreach my $chan (HexChat::get_list("channels")) {
if ($chan->{"type"} == 1 && $chan->{"id"} == HexChat::get_prefs("id")) {
return $chan->{"context"};
}
}
}

Related

How to start/stop a particular session connection

My QuickFIX initiator may manage 5 sessions (targets). I can use ReconnectInterval to control the reconnect-try frequency.
Assume one session connection gives me a problem but I don't want to stop the other 4 connections. I also don't want the problematic session to keep on trying to connect.
Is there any way to stop and later to restart this particular session connection?
Quickfix does not provide an intuitive way to disable a session.
void Initiator::connect()
{
Locker l(m_mutex);
SessionIDs disconnected = m_disconnected;
SessionIDs::iterator i = disconnected.begin();
for ( ; i != disconnected.end(); ++i )
{
Session* pSession = Session::lookupSession( *i );
if ( pSession->isEnabled() && pSession->isSessionTime(UtcTimeStamp()) )
doConnect( *i, m_settings.get( *i ));
}
}
The code above is the loop that keeps trying to maintain all the sessions connected. Looking up to the code, there are two ways to avoid the connection of a session: 1. Disabling the session; 2. Limiting the session time range (there is no way to do it after session initialization, so it's not a valid option).
The method pSession->isEnabled basically returns Session.m_state.m_enabled, but there is no way to access the SessionState object properties, once m_state is private. The only way to set m_enabled to false and avoid the connection tries is by calling Session.logout():
FIX::SessionID session_id("FIX.4.2", "CLIENT1", "EXECUTOR");
FIX::Session* mysession = initiator->getSession(session_id);
mysession->logout();

PERL - Net::Websocket::Server with external periodic event

In my server program I need to have ability to iterate every 5 minutes through all opened connections and see which is really "active" or not.
I know that the best approach is to use "heart beat", but then, the server need to have somehow ability to check weather the connection is "off" in order to delete the associated "user parameters" that is attached to the connection.
My first approach was to use "Async" module, but this works in a separate process - so I cannot delete any element from the main process unless I use a technique to invoke a subroutine from the main process called from the child process (I don't know how, any help will be warmly welcomed).
Another possibility using Async is create a static client that is all the time on (also in the server) and sending "commands" to the server, but to me it looks "too exaggerating" to create such "wasting memory" client in the server, and also "eat" CPU time (I think much more than simple event like equivalent to "setTimeout" in JS).
Yet another approach is to use EV: But when I call EV::run it will NOT RUN anything ELSE than this "periodic event" - means that it will not reach the next line where the ->Start for the server is.
Placing it after the ->Start will make this event useless too: As the server works the program will not go behind the ->Start line.
Using EV::run EV::RUN_NOWAIT; will make the server work, but the EV will somehow not work, for a strange reason (Anyone know how can I still make it work?)
I prefer to not use Net::Websocket::EV, because as per their script, it doesn't do the handshake automatically, and many things (as well as SSL connection that I have) I will need to do manually and for me it is change a lot in my program.
PROBLEM SUMMARY:
How to make the code in EV run every 5 minutes, together with the server?
my %CON; # Connections (And user data) hash
my $__ConChk=EV::periodic 0, 300, 0, sub {
my #l=keys %CON;
for(my $i=0 ; $i<#l ; $i++) {
if($CON{$l[$i]}{"T"}+3600<time()) { # I give one hour time to be completely offline (for different reasons)
$CON{$l[$i]}{"C"}->disconnect(); delete $CON{$l[$i]};
}
}
};
EV::run EV::RUN_NOWAIT; # This is not working - Seems to be ignored!
Net::WebSocket::Server->new(
listen => $ssl, # Earlier preset
silence_max=>60, # Time to just shut the connection off, but don't delete user data
on_connect => sub {
my($serv,$conn)=#_;
my $cid; # Connection ID (for the hash)
$conn->on(
handshake => sub {
my($conn,$handshake)=#_;
# Create user data in $CON{$cid}
},
binary => sub {
$CON{$cid}{"T"}=time();
# Handling of single incomming message (command)
},
disconnect => sub {
# Do NOT DELETE THE ENTRY!! Maybe the connection drop due to instability!!
}
);
}
)->start; # This will run - but ignoring EV::run - what to do....?
undef $__ConChk;

Passing a struct as a command-line argument to a process using execl() function call in C

I am trying to add SSL functionality to my existing TCP echo client-server application.
Earlier in my simple server, I was spawning a new child for every incoming client connection. To this child, I was passing the conn-fd (char*) as a command-line argument. (shown below)
execl("./simple_server_instance", conn_fd, NULL);
Now, for my secure server, I need to pass a CYASSL object (a structure in effect) instead of the conn_fd. (shown below)
ssl = CyaSSL_new(ctx);
CyaSSL_set_fd(ssl, connfd);
Here 'ssl' is the object that needs to be passed to the child process. I tried the following ways to achieve it, but unsuccessful. Is there a simple alternative, or should i go the serialization way?
Typecasting the ssl object to char*
Creating a buffer and doing a memcpy of the entire structure. (shown below)
unsigned char sslobjbuf[sizeof(ssl)];
memcpy(&sslobjbuf, ssl, sizeof(ssl));
execl("./secure_server_instance", "hello", "25", sslobjbuf, NULL );
sdsd
When you execl() a process, you completely replace the running process with the exec'ed process. The exec family of functions expect a sequence of null terminated strings which will become available as arvg[] in the spawned application. You can't just pass arbitrary objects via this interface.
When you probably want to use instead is the fork system call which gives you a new child process which shares its code/data with the parent. The code for ./simple_server_instance would be merged with the main server code. You can do your ssl = CyaSSL_new(ctx); call in the parent process to obtain the object you require, then fork. The parent can then continue to serve new requests while the child runs the the ssl object.
Something like this flow of control may work:
while (1) {
wait_connection();
pid_t child_pid = -1;
ssl = CyaSSL_new(ctx);
child_pid = fork();
if (child_pid == 0) {
/* We're now running the child process which also has access to ssl.
* Run simple_server_instance handler code
*/
}
else {
/* Code running in parent. Do housekeeping, save child_pid if necessary.
* clean up ssl, object, get ready for next connection, handle finished
* child processes.
*/
}
}

Net::Telnet capture error

Below is part of the code
use Net::Telnet;
my $session = new Net::Telnet (Timeout => 15,Prompt => '/#$/');
foreach $node (#nodes) {
$session->open("$node") or die ("\n\n\n NOT ACCESSIBLE ");
$session->login('admin', 'admin');
$session->cmd('term len 0');
my #output1=$session->cmd("sh isis neighbor");
print #output1;
}
Puspose of this script: login to list of nodes and print output
however i see one of the node is not reachable from server and this script stops printing output with below output.
"eof read waiting for login prompt: at telnet-test-rtc1.pl line 11 "
My requirement is even if one of the node is not reachable the script should continue excluding that node.
Is it possible ? Please let me know if more clarity required
regards
In the documentation for Net::Telnet, this can be found:
Errors such as timing-out are handled according to the error mode
action. The default action is to print an error message to standard
error and have the program die. See the errmode() method for more
information.
By setting the errormode appropriately, you can prevent the script from dying.
Telnet is rather aged, technology-wise, though. It might be a good idea to look into SSH instead.
Check the perldoc:
Errors such as timing-out are handled according to the error mode action. The default action is to print an error message to standard error and have the program die. See the errmode() method for more information.
Search "errmode" on that page and you will get what you need.

How do I check if a user is authenticated with NickServ using POE::Component::IRC::State in Perl?

I'm trying to test whether a user is registered on FreeNode. nick_info() doesn't seem to return information about this, so I want to use $irc->yield(whois => $nick); and then grab the irc_whois event's reply. The problem is that I want to wait until this event is fired, so I created a global variable $whois_result and wrote a sub like this:
sub whois {
my $nick = $_[0];
$whois_result = 0;
$irc->yield(whois => $nick);
while($whois_result == 0) { }
return $whois_result;
}
with the irc_whois handler looking like:
sub on_whois {
$whois_result = $_[ARG0];
print "DEBUG: irc_whois fired.\n";
}
Unfortunately, the event can't fire while the loop is running so this hangs. I'm sure there's a better way to do this, but I'm not familiar enough with this kind of programming to know. Any help would be greatly appreciated.
On the sub for states in POE... You have to yield or call it in another state.
Also, when you have data from the IRC command, yield to another state to process it.
_start
- Start up a timer, etc.
timer
- yield on_whois
on_whois
- run who is
- Set data
- yield to the next timer
_stop
- Kill the timer
- flush the data
I run a bot on Freenode and resolved the issue by asking Nickserv the command:
ACC [nick] *
Nickserv will then reply with a notice in the format:
[nickname] -> [registerd nickservname] ACC [level]
Where level 3 means that the user is identified to nickserv.
The following applies to FreeNode at least (or any server supporting the identify-msg feature).
If you are reacting to a message (irc_msg, irc_public, or irc_ctcp_action) from a user, you can tell whether he has identified to NickServ by looking at the third argument ($_[ARG3]) provided to the event handler. It will be true if the user has identified, false otherwise.