<commit_before><?php

#####################################################################################################

function initialize_irc_connection()
{
  rawmsg("NICK ".NICK);
  rawmsg("USER ".USER_NAME." hostname servername :".FULL_NAME);
}

#####################################################################################################

function initialize_socket()
{
  return initialize_socket1();
}

#####################################################################################################

function initialize_socket1()
{
  if (IRC_PORT=="6697")
  {
    $socket=fsockopen("ssl://".IRC_HOST_CONNECT,IRC_PORT);
  }
  else
  {
    $socket=fsockopen(IRC_HOST_CONNECT,IRC_PORT);
  }
  if ($socket===False)
  {
    term_echo("ERROR CREATING IRC SOCKET");
    die();
  }
  else
  {
    stream_set_blocking($socket,0);
  }
  echo $socket."\n";
  return $socket;
}

#####################################################################################################

function initialize_socket2()
{
  if (file_exists(EXEC_SOCK_FILE)==True)
  {
    $inode_check=file_get_contents(EXEC_SOCK_FILE);
    echo "SOCKET INDODE FROM FILE: $inode_check\n";
    $pid=getmypid();
    $ip=gethostbyname(IRC_HOST_CONNECT);
    $ip_parts=explode(".",$ip);
    $ip_hex=dechex($ip_parts[3]).dechex($ip_parts[2]).dechex($ip_parts[1]).dechex($ip_parts[0]);
    $port_hex=dechex(IRC_PORT);
    $tcp=file_get_contents("/proc/$pid/net/tcp");
    $fds=explode(PHP_EOL,$tcp);
    for ($i=0;$i<count($fds);$i++)
    {
      $line=trim($fds[$i]);
      echo "$line\n";
      $parts=explode(" ",$line);
      for ($j=0;$j<count($parts);$j++)
      {
        if ($parts[$j]=="")
        {
          unset($parts[$j]);
        }
      }
      $parts=array_values($parts);
      $remote=$parts[2];
      if (($remote==strtoupper("$ip_hex:$port_hex")) and (count($parts)>9))
      {
        $inode=$parts[9];
        echo "SOCKET INDODE FROM PROC: $inode\n";
        /*if ($inode<>$inode_check)
        {
          unlink(EXEC_SOCK_FILE);
          die("ERROR: SOCKET INODE MISMATCH\n");
        }*/
        $fd="";
        $path="/proc/$pid/fd";
        $handle=opendir($path);
        while (($fn=readdir($handle))!==False)
        {
          $full=$path."/".$fn;
          if ((is_dir($full)==False) and ($fn<>".") and ($fn<>".."))
          {
            if (fileinode($full)==$inode)
            {
              $fd=$full;
              break;
            }
          }
        }
        closedir($handle);
        if ($fd=="")
        {
          unlink(EXEC_SOCK_FILE);
          die("ERROR: SOCKET FILE DESCRIPTOR NOT FOUND\n");
        }
        $socket=fsockopen("unix://$fd",0);
        #$socket=fopen($fd,"rw");
        stream_set_blocking($socket,0);
        break;
      }
    }
  }
  else
  {
    $socket=initialize_socket1();
  }
  return $socket;
}

#####################################################################################################

function finalize_socket()
{
  finalize_socket1();
}

#####################################################################################################

function finalize_socket1()
{
  global $socket;
  rawmsg("NickServ LOGOUT");
  rawmsg("QUIT :dafuq");
  fclose($socket);
}

#####################################################################################################

function finalize_socket2()
{
  global $socket;
  if (defined("RESTART")==True)
  {
    file_put_contents(EXEC_SOCK_FILE,intval($socket));
  }
  else
  {
    finalize_socket1();
  }
}

#####################################################################################################

function initialize_buckets()
{
  global $buckets;
  $empty=array();
  $buckets[BUCKET_EVENT_HANDLERS]=serialize($empty);
  $buckets[BUCKET_CONNECTION_ESTABLISHED]="0";
  $buckets[BUCKET_USERS]=serialize($empty);
}

#####################################################################################################

function init()
{
  $items=parse_data(CMD_INIT);
  buckets_load($items);
  initialize_buckets();
  #handle_data(CMD_INIT."\n",False,False,True);
  process_exec_inits();
  process_scripts($items,ALIAS_INIT);
}

#####################################################################################################

function process_exec_inits()
{
  global $init;
  term_echo("init:");
  $file_lines=array();
  for ($i=0;$i<count($init);$i++)
  {
    load_directory($init[$i],$file_lines,FILE_DIRECTIVE_INIT);
  }
  foreach ($file_lines as $filename => $commands)
  {
    for ($i=0;$i<count($commands);$i++)
    {
      term_echo("FILE INIT: $filename =>".$commands[$i]);
      handle_data(":".NICK." ".CMD_INTERNAL." :".$commands[$i]."\n",False,False,True);
    }
  }
  unset($file_lines);
}

#####################################################################################################

function startup()
{
  global $buckets;
  $buckets[BUCKET_CONNECTION_ESTABLISHED]="1";
  process_exec_startups();
  $items=parse_data(CMD_STARTUP);
  process_scripts($items,ALIAS_STARTUP);
}

#####################################################################################################

function process_exec_startups()
{
  global $startup;
  term_echo("startup:");
  $file_lines=array();
  for ($i=0;$i<count($startup);$i++)
  {
    load_directory($startup[$i],$file_lines,FILE_DIRECTIVE_STARTUP);
  }
  foreach ($file_lines as $filename => $commands)
  {
    for ($i=0;$i<count($commands);$i++)
    {
      term_echo("FILE STARTUP: ".$commands[$i]);
      handle_data(":".NICK." ".CMD_INTERNAL." :".$commands[$i]."\n",False,False,True);
    }
  }
  unset($file_lines);
}

#####################################################################################################

function get_valid_data_cmd($allow_customs=True)
{
  /*
  "000" = <command>
  "001" = <command> :<trailing>
  "010" = <command> <params>
  "011" = <command> <params> :<trailing>
  "100" = :<prefix> <command>
  "101" = :<prefix> <command> :<trailing>
  "110" = :<prefix> <command> <params>
  "111" = :<prefix> <command> <params> :<trailing>
  ORDER MASKS IN ORDER FROM 000 TO 111: STDOUT PREFIX WILL SELECT LAST (MOST VERBOSE) MASK FOR OUTPUT TO IRC
  # = NUMERIC
  */
  $result=array(
    "#"=>array("101","110","111"),
    "INVITE"=>array("111"),
    "JOIN"=>array("110"),
    "KICK"=>array("110","111"),
    "KILL"=>array("101"),
    "MODE"=>array("101","110","111"),
    "NICK"=>array("101"),
    "NOTICE"=>array("111"),
    "PART"=>array("110","111"),
    "WHOIS"=>array("010","110"),
    "PRIVMSG"=>array("011","111"),
    "QUIT"=>array("100","101"),
    "PONG"=>array("110","111"));
  if ($allow_customs==True)
  {
    $customs=get_valid_custom_cmd();
    $result=array_merge($result,$customs);
  }
  return $result;
}

#####################################################################################################

function get_valid_custom_cmd()
{
  $result=array(
    CMD_INIT=>array("000"),
    CMD_STARTUP=>array("000"),
    CMD_INTERNAL=>array("100","101","110","111"),
    CMD_BUCKET_GET=>array("001","101"),
    CMD_BUCKET_SET=>array("001","101"),
    CMD_BUCKET_UNSET=>array("001","101"),
    CMD_BUCKET_APPEND=>array("001","101"),
    CMD_BUCKET_LIST=>array("000","100"),
    CMD_PAUSE=>array("000"),
    CMD_UNPAUSE=>array("000"));
  return $result;
}

#####################################################################################################

function get_list($items)
{
  global $exec_list;
  global $reserved_aliases;
  $msg=" ~list ~list-auth ~lock ~unlock";
  privmsg($items["destination"],$items["nick"],$msg);
  $msg="";
  foreach ($exec_list as $alias => $data)
  {
    if ((count($data["accounts"])==0) and (strlen($alias)<=20) and (in_array($alias,$reserved_aliases)==False) and ((count($data["cmds"])==0) or (in_array("PRIVMSG",$data["cmds"])==True)))
    {
      if ($msg<>"")
      {
        $msg=$msg." ";
      }
      if (strlen($msg.$alias)>(MAX_MSG_LENGTH-1))
      {
        privmsg($items["destination"],$items["nick"]," ".$msg);
        $msg=$alias;
      }
      else
      {
        $msg=$msg.$alias;
      }
    }
  }
  privmsg($items["destination"],$items["nick"]," ".$msg);
}

#####################################################################################################

function get_list_auth($items)
{
  global $exec_list;
  global $reserved_aliases;
  $msg=" ~q ~rehash ~ps ~kill ~killall ~dest-override ~dest-clear ~buckets-dump ~buckets-save ~buckets-load ~buckets-flush ~buckets-list ~restart ~ignore ~unignore";
  privmsg($items["destination"],$items["nick"],$msg);
  $msg="";
  foreach ($exec_list as $alias => $data)
  {
    if ((count($data["accounts"])>0) and (strlen($alias)<=20) and (in_array($alias,$reserved_aliases)==False) and ((count($data["cmds"])==0) or (in_array("PRIVMSG",$data["cmds"])==True)))
    {
      if ($msg<>"")
      {
        $msg=$msg." ";
      }
      if (strlen($msg.$alias)>(MAX_MSG_LENGTH-1))
      {
        privmsg($items["destination"],$items["nick"]," ".$msg);
        $msg=$alias;
      }
      else
      {
        $msg=$msg.$alias;
      }
    }
  }
  privmsg($items["destination"],$items["nick"]," ".$msg);
}

#####################################################################################################

function handle_errors($data)
{
  global $buckets;
  if (isset($buckets[BUCKET_CONNECTION_ESTABLISHED])==False)
  {
    return;
  }
  $msg=trim($data,"\n\r\0\x0B");
  $lmsg=strtolower($msg);
  if ((DEBUG_CHAN<>"") and (strpos($lmsg,DEBUG_CHAN)===False) and ($buckets[BUCKET_CONNECTION_ESTABLISHED]<>"0"))
  {
    # TODO: only output if occurs at the start of line
    if ((strpos($lmsg,"php parse error:")!==False) or (strpos($lmsg,"php warning:")!==False) or (strpos($lmsg,"php fatal error:")!==False) or (strpos($lmsg,"php notice:")!==False))
    {
      rawmsg(":".NICK." PRIVMSG ".DEBUG_CHAN." :$msg");
    }
  }
}

#####################################################################################################

function log_items($items)
{
  if ((BOT_SCHEMA=="") or (LOG_TABLE==""))
  {
    return;
  }
  sql_insert($items,LOG_TABLE);
}

#####################################################################################################

function handle_direct_stdin()
{
  global $direct_stdin;
  global $irc_pause;
  $msg=trim(fgets($direct_stdin));
  if ($msg=="")
  {
    return;
  }
  term_echo("*** DIRECT STDIN: $msg");
  $parts=explode(" ",$msg);
  $prefix=strtoupper($parts[0]);
  array_shift($parts);
  $prefix_msg=implode(" ",$parts);
  if ($prefix_msg<>"")
  {
    switch ($prefix)
    {
      case PREFIX_IRC:
        rawmsg($prefix_msg);
        return;
      case PREFIX_INTERNAL:
        $nick=NICK;
        handle_data(":$nick ".CMD_INTERNAL." :".$prefix_msg."\n",False,False,True);
        return;
      case PREFIX_PAUSE:
        $irc_pause=True;
        return;
      case PREFIX_UNPAUSE:
        $irc_pause=False;
        return;
    }
  }
  handle_data($msg."\n",False,False,True);
}

#####################################################################################################

function handle_process($handle)
{
  global $reserved_aliases;
  global $silent_timeout_commands;
  handle_stdout($handle);
  handle_stderr($handle);
  $flag=False;
  if ($handle["pipe_stdout"]===Null)
  {
    $flag=True;
  }
  else
  {
    $meta=stream_get_meta_data($handle["pipe_stdout"]);
    if ($meta["eof"]==True)
    {
      $flag=True;
    }
  }
  if ($flag==True)
  {
    write_out_buffer_proc($handle,"","proc_end");
    free_bucket_locks($handle["pid"]);
    fclose($handle["pipe_stdin"]);
    fclose($handle["pipe_stdout"]);
    fclose($handle["pipe_stderr"]);
    proc_close($handle["process"]);
    if ($handle["alias"]<>ALIAS_ALL)
    {
      #term_echo("process terminated normally: ".$handle["command"]);
    }
    return False;
  }
  if ($handle["timeout"]>0)
  {
    if ((microtime(True)-$handle["start"])>$handle["timeout"])
    {
      write_out_buffer_proc($handle,"","proc_timeout");
      free_bucket_locks($handle["pid"]);
      kill_process($handle);
      term_echo("process timed out: ".$handle["command"]);
      $msg="process timed out: ".$handle["alias"]." ".$handle["trailing"];
      if ((in_array($handle["alias"],$reserved_aliases)==False) and (in_array($handle["cmd"],$silent_timeout_commands)==False))
      {
        privmsg($handle["destination"],$handle["nick"],$msg);
      }
      privmsg(OPERATOR_ACCOUNT,"",$msg);
      return False;
    }
  }
  return True;
}

#####################################################################################################

function free_bucket_locks($pid)
{
  global $bucket_locks;
  foreach ($bucket_locks as $bucket_index => $pid_array)
  {
    $key=array_search($pid,$pid_array);
    if ($key!==False)
    {
      unset($pid_array[$key]);
      if (count($pid_array)==0)
      {
        unset($bucket_locks[$bucket_index]);
        term_echo("BUCKET UNLOCKED: $bucket_index BY $pid [STILL LOCKED BY OTHER PROCESS]");
      }
      else
      {
        term_echo("BUCKET UNLOCKED: $bucket_index BY $pid [NO LONGER LOCKED BY ANY PROCESSES]");
      }
    }
  }
}

#####################################################################################################

function write_out_buffer($buf)
{
  # use "cat exec_iface" to follow (tail -f no worka for some reason)
  global $out_buffer;
  if (flock($out_buffer,LOCK_EX)==True)
  {
    $buf=str_replace(chr(13),"",$buf);
    $buf=str_replace(chr(10),"",$buf);
    fwrite($out_buffer,serialize($buf)."\n");
  }
  flock($out_buffer,LOCK_UN);
}

#####################################################################################################

function write_out_buffer_proc($handle,$buf,$type)
{
  $data=array();
  $data["type"]=$type;
  $data["buf"]=$buf;
  $data["handle"]=$handle;
  $data["time"]=microtime(True);
  write_out_buffer($data);
}

#####################################################################################################

function write_out_buffer_command($items,$command)
{
  $data=array();
  $data["type"]="command";
  $data["buf"]=$command;
  $data["items"]=$items;
  $data["time"]=microtime(True);
  write_out_buffer($data);
}

#####################################################################################################

function write_out_buffer_data($items)
{
  $data=array();
  $data["type"]="data";
  $data["buf"]=$items["trailing"];
  $data["items"]=$items;
  $data["time"]=microtime(True);
  write_out_buffer($data);
}

#####################################################################################################

function write_out_buffer_sock($buf)
{
  $data=array();
  $data["type"]="socket";
  $data["buf"]=$buf;
  $data["time"]=microtime(True);
  write_out_buffer($data);
}

#####################################################################################################

function handle_reader_stdout_command($handle,$prefix)
{
  global $exec_list;
  global $buckets;
  global $handles;
  switch ($prefix)
  {
    case PREFIX_READER_EXEC_LIST:
      foreach ($exec_list as $alias => $data)
      {
        $data=array();
        $data["type"]="reader_exec_list";
        $data["buf"]=$data;
        $data["time"]=microtime(True);
        write_out_buffer($data);   
      }   
      return;
    case PREFIX_READER_BUCKETS:
      foreach ($buckets as $index => $value)
      {
        $data=array();
        $data["type"]="reader_buckets";
        $data["buf"]=$value;<commit_msg>whatever i changed<commit_after><?php

#####################################################################################################

function initialize_irc_connection()
{
  rawmsg("NICK ".NICK);
  rawmsg("USER ".USER_NAME." hostname servername :".FULL_NAME);
}

#####################################################################################################

function initialize_socket()
{
  return initialize_socket1();
}

#####################################################################################################

function initialize_socket1()
{
  if (IRC_PORT=="6697")
  {
    $socket=fsockopen("ssl://".IRC_HOST_CONNECT,IRC_PORT);
  }
  else
  {
    $socket=fsockopen(IRC_HOST_CONNECT,IRC_PORT);
  }
  if ($socket===False)
  {
    term_echo("ERROR CREATING IRC SOCKET");
    die();
  }
  else
  {
    stream_set_blocking($socket,0);
  }
  echo $socket."\n";
  return $socket;
}

#####################################################################################################

function initialize_socket2()
{
  if (file_exists(EXEC_SOCK_FILE)==True)
  {
    $inode_check=file_get_contents(EXEC_SOCK_FILE);
    echo "SOCKET INDODE FROM FILE: $inode_check\n";
    $pid=getmypid();
    $ip=gethostbyname(IRC_HOST_CONNECT);
    $ip_parts=explode(".",$ip);
    $ip_hex=dechex($ip_parts[3]).dechex($ip_parts[2]).dechex($ip_parts[1]).dechex($ip_parts[0]);
    $port_hex=dechex(IRC_PORT);
    $tcp=file_get_contents("/proc/$pid/net/tcp");
    $fds=explode(PHP_EOL,$tcp);
    for ($i=0;$i<count($fds);$i++)
    {
      $line=trim($fds[$i]);
      echo "$line\n";
      $parts=explode(" ",$line);
      for ($j=0;$j<count($parts);$j++)
      {
        if ($parts[$j]=="")
        {
          unset($parts[$j]);
        }
      }
      $parts=array_values($parts);
      $remote=$parts[2];
      if (($remote==strtoupper("$ip_hex:$port_hex")) and (count($parts)>9))
      {
        $inode=$parts[9];
        echo "SOCKET INDODE FROM PROC: $inode\n";
        /*if ($inode<>$inode_check)
        {
          unlink(EXEC_SOCK_FILE);
          die("ERROR: SOCKET INODE MISMATCH\n");
        }*/
        $fd="";
        $path="/proc/$pid/fd";
        $handle=opendir($path);
        while (($fn=readdir($handle))!==False)
        {
          $full=$path."/".$fn;
          if ((is_dir($full)==False) and ($fn<>".") and ($fn<>".."))
          {
            if (fileinode($full)==$inode)
            {
              $fd=$full;
              break;
            }
          }
        }
        closedir($handle);
        if ($fd=="")
        {
          unlink(EXEC_SOCK_FILE);
          die("ERROR: SOCKET FILE DESCRIPTOR NOT FOUND\n");
        }
        $socket=fsockopen("unix://$fd",0);
        #$socket=fopen($fd,"rw");
        stream_set_blocking($socket,0);
        break;
      }
    }
  }
  else
  {
    $socket=initialize_socket1();
  }
  return $socket;
}

#####################################################################################################

function finalize_socket()
{
  finalize_socket1();
}

#####################################################################################################

function finalize_socket1()
{
  global $socket;
  rawmsg("NickServ LOGOUT");
  rawmsg("QUIT :dafuq");
  fclose($socket);
}

#####################################################################################################

function finalize_socket2()
{
  global $socket;
  if (defined("RESTART")==True)
  {
    file_put_contents(EXEC_SOCK_FILE,intval($socket));
  }
  else
  {
    finalize_socket1();
  }
}

#####################################################################################################

function initialize_buckets()
{
  global $buckets;
  $empty=array();
  $buckets[BUCKET_EVENT_HANDLERS]=serialize($empty);
  $buckets[BUCKET_CONNECTION_ESTABLISHED]="0";
  $buckets[BUCKET_USERS]=serialize($empty);
}

#####################################################################################################

function init()
{
  $items=parse_data(CMD_INIT);
  buckets_load($items);
  initialize_buckets();
  #handle_data(CMD_INIT."\n",False,False,True);
  process_exec_inits();
  process_scripts($items,ALIAS_INIT);
}

#####################################################################################################

function process_exec_inits()
{
  global $init;
  term_echo("init:");
  $file_lines=array();
  for ($i=0;$i<count($init);$i++)
  {
    load_directory($init[$i],$file_lines,FILE_DIRECTIVE_INIT);
  }
  foreach ($file_lines as $filename => $commands)
  {
    for ($i=0;$i<count($commands);$i++)
    {
      term_echo("FILE INIT: $filename =>".$commands[$i]);
      handle_data(":".NICK." ".CMD_INTERNAL." :".$commands[$i]."\n",False,False,True);
    }
  }
  unset($file_lines);
}

#####################################################################################################

function startup()
{
  global $buckets;
  $buckets[BUCKET_CONNECTION_ESTABLISHED]="1";
  process_exec_startups();
  $items=parse_data(CMD_STARTUP);
  process_scripts($items,ALIAS_STARTUP);
}

#####################################################################################################

function process_exec_startups()
{
  global $startup;
  term_echo("startup:");
  $file_lines=array();
  for ($i=0;$i<count($startup);$i++)
  {
    load_directory($startup[$i],$file_lines,FILE_DIRECTIVE_STARTUP);
  }
  foreach ($file_lines as $filename => $commands)
  {
    for ($i=0;$i<count($commands);$i++)
    {
      term_echo("FILE STARTUP: ".$commands[$i]);
      handle_data(":".NICK." ".CMD_INTERNAL." :".$commands[$i]."\n",False,False,True);
    }
  }
  unset($file_lines);
}

#####################################################################################################

function get_valid_data_cmd($allow_customs=True)
{
  /*
  "000" = <command>
  "001" = <command> :<trailing>
  "010" = <command> <params>
  "011" = <command> <params> :<trailing>
  "100" = :<prefix> <command>
  "101" = :<prefix> <command> :<trailing>
  "110" = :<prefix> <command> <params>
  "111" = :<prefix> <command> <params> :<trailing>
  ORDER MASKS IN ORDER FROM 000 TO 111: STDOUT PREFIX WILL SELECT LAST (MOST VERBOSE) MASK FOR OUTPUT TO IRC
  # = NUMERIC
  */
  $result=array(
    "#"=>array("101","110","111"),
    "INVITE"=>array("111"),
    "JOIN"=>array("110"),
    "KICK"=>array("110","111"),
    "KILL"=>array("101"),
    "MODE"=>array("101","110","111"),
    "NICK"=>array("101"),
    "NOTICE"=>array("111"),
    "PART"=>array("110","111"),
    "WHOIS"=>array("010","110"),
    "PRIVMSG"=>array("011","111"),
    "QUIT"=>array("100","101"),
    "PONG"=>array("110","111"));
  if ($allow_customs==True)
  {
    $customs=get_valid_custom_cmd();
    $result=array_merge($result,$customs);
  }
  return $result;
}

#####################################################################################################

function get_valid_custom_cmd()
{
  $result=array(
    CMD_INIT=>array("000"),
    CMD_STARTUP=>array("000"),
    CMD_INTERNAL=>array("100","101","110","111"),
    CMD_BUCKET_GET=>array("001","101"),
    CMD_BUCKET_SET=>array("001","101"),
    CMD_BUCKET_UNSET=>array("001","101"),
    CMD_BUCKET_APPEND=>array("001","101"),
    CMD_BUCKET_LIST=>array("000","100"),
    CMD_PAUSE=>array("000"),
    CMD_UNPAUSE=>array("000"));
  return $result;
}

#####################################################################################################

function get_list($items)
{
  global $exec_list;
  global $reserved_aliases;
  $msg=" ~list ~list-auth ~lock ~unlock";
  privmsg($items["destination"],$items["nick"],$msg);
  $msg="";
  foreach ($exec_list as $alias => $data)
  {
    if ((count($data["accounts"])==0) and (strlen($alias)<=20) and (in_array($alias,$reserved_aliases)==False) and ((count($data["cmds"])==0) or (in_array("PRIVMSG",$data["cmds"])==True)))
    {
      if ($msg<>"")
      {
        $msg=$msg." ";
      }
      if (strlen($msg.$alias)>(MAX_MSG_LENGTH-1))
      {
        privmsg($items["destination"],$items["nick"]," ".$msg);
        $msg=$alias;
      }
      else
      {
        $msg=$msg.$alias;
      }
    }
  }
  privmsg($items["destination"],$items["nick"]," ".$msg);
}

#####################################################################################################

function get_list_auth($items)
{
  global $exec_list;
  global $reserved_aliases;
  $msg=" ~q ~rehash ~ps ~kill ~killall ~dest-override ~dest-clear ~buckets-dump ~buckets-save ~buckets-load ~buckets-flush ~buckets-list ~restart ~ignore ~unignore";
  privmsg($items["destination"],$items["nick"],$msg);
  $msg="";
  foreach ($exec_list as $alias => $data)
  {
    if ((count($data["accounts"])>0) and (strlen($alias)<=20) and (in_array($alias,$reserved_aliases)==False) and ((count($data["cmds"])==0) or (in_array("PRIVMSG",$data["cmds"])==True)))
    {
      if ($msg<>"")
      {
        $msg=$msg." ";
      }
      if (strlen($msg.$alias)>(MAX_MSG_LENGTH-1))
      {
        privmsg($items["destination"],$items["nick"]," ".$msg);
        $msg=$alias;
      }
      else
      {
        $msg=$msg.$alias;
      }
    }
  }
  privmsg($items["destination"],$items["nick"]," ".$msg);
}

#####################################################################################################

function handle_errors($data)
{
  global $buckets;
  if (isset($buckets[BUCKET_CONNECTION_ESTABLISHED])==False)
  {
    return;
  }
  $msg=trim($data,"\n\r\0\x0B");
  $lmsg=strtolower($msg);
  if ((DEBUG_CHAN<>"") and (strpos($lmsg,DEBUG_CHAN)===False) and ($buckets[BUCKET_CONNECTION_ESTABLISHED]<>"0"))
  {
    # TODO: only output if occurs at the start of line
    if ((strpos($lmsg,"php parse error:")!==False) or (strpos($lmsg,"php warning:")!==False) or (strpos($lmsg,"php fatal error:")!==False) or (strpos($lmsg,"php notice:")!==False))
    {
      rawmsg(":".NICK." PRIVMSG ".DEBUG_CHAN." :$msg");
    }
  }
}

#####################################################################################################

function log_items($items)
{
  if ((BOT_SCHEMA=="") or (LOG_TABLE==""))
  {
    return;
  }
  sql_insert($items,LOG_TABLE);
}

#####################################################################################################

function handle_direct_stdin()
{
  global $direct_stdin;
  global $irc_pause;
  $msg=trim(fgets($direct_stdin));
  if ($msg=="")
  {
    return;
  }
  term_echo("*** DIRECT STDIN: $msg");
  $parts=explode(" ",$msg);
  $prefix=strtoupper($parts[0]);
  array_shift($parts);
  $prefix_msg=implode(" ",$parts);
  if ($prefix_msg<>"")
  {
    switch ($prefix)
    {
      case PREFIX_IRC:
        rawmsg($prefix_msg);
        return;
      case PREFIX_INTERNAL:
        $nick=NICK;
        handle_data(":$nick ".CMD_INTERNAL." :".$prefix_msg."\n",False,False,True);
        return;
      case PREFIX_PAUSE:
        $irc_pause=True;
        return;
      case PREFIX_UNPAUSE:
        $irc_pause=False;
        return;
    }
  }
  handle_data($msg."\n",False,False,True);
}

#####################################################################################################

function handle_process($handle)
{
  global $reserved_aliases;
  global $silent_timeout_commands;
  handle_stdout($handle);
  handle_stderr($handle);
  $flag=False;
  if ($handle["pipe_stdout"]===Null)
  {
    $flag=True;
  }
  else
  {
    $meta=stream_get_meta_data($handle["pipe_stdout"]);
    if ($meta["eof"]==True)
    {
      $flag=True;
    }
  }
  if ($flag==True)
  {
    write_out_buffer_proc($handle,"","proc_end");
    free_bucket_locks($handle["pid"]);
    fclose($handle["pipe_stdin"]);
    fclose($handle["pipe_stdout"]);
    fclose($handle["pipe_stderr"]);
    proc_close($handle["process"]);
    if ($handle["alias"]<>ALIAS_ALL)
    {
      #term_echo("process terminated normally: ".$handle["command"]);
    }
    return False;
  }
  if ($handle["timeout"]>0)
  {
    if ((microtime(True)-$handle["start"])>$handle["timeout"])
    {
      write_out_buffer_proc($handle,"","proc_timeout");
      free_bucket_locks($handle["pid"]);
      kill_process($handle);
      term_echo("process timed out: ".$handle["command"]);
      $msg="process timed out: ".$handle["alias"]." ".$handle["trailing"];
      if ((in_array($handle["alias"],$reserved_aliases)==False) and (in_array($handle["cmd"],$silent_timeout_commands)==False))
      {
        privmsg($handle["destination"],$handle["nick"],$msg);
      }
      privmsg(OPERATOR_ACCOUNT,"",$msg);
      return False;
    }
  }
  return True;
}

#####################################################################################################

function free_bucket_locks($pid)
{
  global $bucket_locks;
  foreach ($bucket_locks as $bucket_index => $pid_array)
  {
    $key=array_search($pid,$pid_array);
    if ($key!==False)
    {
      unset($pid_array[$key]);
      if (count($pid_array)==0)
      {
        unset($bucket_locks[$bucket_index]);
        term_echo("BUCKET UNLOCKED: $bucket_index BY $pid [STILL LOCKED BY OTHER PROCESS]");
      }
      else
      {
        term_echo("BUCKET UNLOCKED: $bucket_index BY $pid [NO LONGER LOCKED BY ANY PROCESSES]");
      }
    }
  }
}

#####################################################################################################

function write_out_buffer($buf)
{
  # use "cat exec_iface" to follow (tail -f no worka for some reason)
  global $out_buffer;
  if (flock($out_buffer,LOCK_EX)==True)
  {
    $buf=str_replace(chr(13),"",$buf);
    $buf=str_replace(chr(10),"",$buf);
    fwrite($out_buffer,serialize($buf)."\n");
  }
  flock($out_buffer,LOCK_UN);
}

#####################################################################################################

function write_out_buffer_proc($handle,$buf,$type)
{
  $data=array();
  $data["type"]=$type;
  $data["buf"]=$buf;
  $data["handle"]=$handle;
  $data["time"]=microtime(True);
  write_out_buffer($data);
}

#####################################################################################################

function write_out_buffer_command($items,$command)
{
  $data=array();
  $data["type"]="command";
  $data["buf"]=$command;
  $data["items"]=$items;
  $data["time"]=microtime(True);
  write_out_buffer($data);
}

#####################################################################################################

function write_out_buffer_data($items)
{
  $data=array();
  $data["type"]="data";
  $data["buf"]=$items["trailing"];
  $data["items"]=$items;
  $data["time"]=microtime(True);
  write_out_buffer($data);
}

#####################################################################################################

function write_out_buffer_sock($buf)
{
  $data=array();
  $data["type"]="socket";
  $data["buf"]=$buf;
  $data["time"]=microtime(True);
  write_out_buffer($data);
}

#####################################################################################################

function handle_reader_stdout_command($handle,$prefix)
{
  global $exec_list;
  global $buckets;
  global $handles;
  switch ($prefix)
  {
    case PREFIX_READER_EXEC_LIST:
      foreach ($exec_list as $alias => $exec_data)
      {
        $data=array();
        $data["type"]="reader_exec_list";
        $data["buf"]=$exec_data;
        $data["time"]=microtime(True);
        write_out_buffer($data);   
      }   
      return;
    case PREFIX_READER_BUCKETS:
      foreach ($buckets as $index => $value)
      {
        $data=array();
        $data["type"]="reader_buckets";
        $data["buf"]=$value;
{'fraction_non_alphanumeric': 0.3445071785771899, 'fraction_numerical': 0.013098886917244717, 'mean_word_length': 4.636661211129296, 'pattern_counts': {'":': 8, '<': 79, '<?xml version=': 0, '>': 135, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2697690', 'n_tokens_mistral': 10452, 'n_tokens_neox': 9887, 'n_words': 1331}