ftp issues with symlinks and directories with dots in their name

I’ve found that certain windows FTP clients like cuteFTP in their default configuration have issues with directory names wiht dots in (such as ~/sites/domain.com) where the file is actaully a symlink somewhere else.

In one of my setups, I do this…

~user/sites/domain.com -> symlink to -> /var/www/domain.com

This was causing issues, to work around it, I had 2 options…..

~user/sites/domain_com -> symlink to -> /var/www/domain.com

or…

~user/sites/domain.com/htdocs -> symlink to -> /var/www/domain.com/htdocs

Some windows software really does suck.

Dynamic HTML_QuickForm Example

Recently I created a dynamically changing HTML_QuickForm (aka HTML_QF, the PEAR module). I have posted it on my site for others to see, as it might come in useful for someone some day.

Please note – this is not final working code, this is an example only. Anyone looking for a RADIUS frontend, this won’t do what you need.

<?php

    require_once 'HTML/QuickForm.php';

    class radForm extends  HTML_QuickForm
    {
        // private var to maintain the viewstate.
        var $_viewstate;

        /**
         *
         * Class constructor
         *
         * Sets up the main form elements, calls the action handler, and renders the extra
         * elements based upon the viewstate.
         */
        function radForm()
        {
            $this->HTML_QuickForm('RadUser');

            // recover the viewstate from the hidden form element
            $this->addElement('hidden', '__VIEWSTATE');
            if ($this->getSubmitValue('__VIEWSTATE'))
            {
                $this->_viewstate = unserialize(base64_decode($this->getSubmitValue('__VIEWSTATE')));
            }
            else
            {
                // defaults it to being an array if not already set
                $this->_viewstate = array();
            }

            // this is added for the javascript to change to allow the action handler (serverside)
            // to read it
            $action =& $this->createElement('hidden', 'action');
            $this->addElement($action);

            // adds the default fields
            $this->addElement('header', null, 'RADIUS Admin');
            $this->addElement('text', 'onsite_id', 'OnSite Ref');
            $this->addElement('text', 'cbuk', 'CBUK');
            $this->addElement('text', 'phonenum', 'Phone Number');
            $this->addElement('text', 'username', 'Username');
            $this->addElement('checkbox', 'active', 'Active');

            // add the select box to allow adding profiles
            $this->addElement('header', null, 'Add Profile');
            $options = array_merge(array(0 => ' -- select a profile -- '), $this->_getProfiles());
            // this adds a JS onchange function to call the serverside actionhandler.
            $this->addElement('select', 'addProfile', 'Add Profile', $options, 'onchange="submitWithAction(\'profileAdd\',this)"');

            // call the action handler
            $this->_actionHandler();

            // this function renders the extra form elements that have been added
            $this->processViewstate();
            $this->_updateViewstate();
            $this->addElement('submit', 'post', 'Submit');
        }

        /**
         *
         * Goes though each profile and adds the profile section to the form
         */
        function processViewstate()
        {
            if (isset($this->_viewstate['profiles']))
            {
                foreach ($this->_viewstate['profiles'] as $profileName => $profileFields)
                {
                    $this->addProfileGroup($profileName, $profileName);
                }
            }
        }

        /**
         *
         * Adds the group select and check/reply options to the form.
         */
        function addProfileGroup($prefix, $name)
        {
            static $index;
            isset($index)?$index++:$index=0;

            // profile title and remove link
            $removeLink = '<a href="#" onclick="submitWithAction(\'profileDel|' . $prefix . '\'); return false;" >remove</a>';
            $this->addElement('header', null, 'Profile ' . $name . ' - '  .  $removeLink);

            // group selector
            $options = array_merge( array(0 => ' -- select a group -- '), $this->_getGroups());
            $this->addElement('select', 'groupAdd[' . $prefix . ']', 'Current Group', $options, 'onchange="submitWithAction(\'groupSet|' . $prefix . '\', this)"');

            // checks
            $options = array_merge( array(0 => ' -- select a check -- '), $this->_getChecks());
            $this->addElement('select', 'checkAdd[' . $prefix . ']', 'Checks', $options, 'onchange="submitWithAction(\'checkAdd|' . $prefix . '\', this)"');
            if (isset($this->_viewstate['profiles'][$prefix]['check']['elements']))
            {
                foreach ($this->_viewstate['profiles'][$prefix]['check']['elements'] as $index => $element)
                {
                    $group = array();
                    $group[] = $this->createElement('select', 'op', null, $this->_getOperators());
                    $group[] = $this->createElement('text', 'value', $element);
                    $group[] = $this->createElement('submit', null, 'remove'    , 'onclick="submitWithAction(\'checkDelete|' . $prefix . '|' . $index . '\')"');
                    $this->addGroup($group, $prefix . '_checks' . $index, $element);
                }
            }

            // replies
            $options = array_merge( array(0 => ' -- select a reply -- '), $this->_getReplies());
            $this->addElement('select', 'replyAdd[' . $prefix . ']', 'Replies', $options, 'onchange="submitWithAction(\'replyAdd|' . $prefix . '\', this)"');
            if (isset($this->_viewstate['profiles'][$prefix]['reply']['elements']))
            {
                foreach ($this->_viewstate['profiles'][$prefix]['reply']['elements'] as $index => $element)
                {
                    $group = array();
                    $group[] = $this->createElement('select', 'op', null, $this->_getOperators());
                    $group[] = $this->createElement('text', 'value', $element);
                    $group[] = $this->createElement('submit', null, 'remove', 'onclick="submitWithAction(\'replyDelete|' . $prefix . '|' . $index . '\')"');
                    $this->addGroup($group, $prefix . '_replys' . $index, $element);
                }
            }


        }

        /**
         *
         *  Function to update the viewstate
         */
        function _updateViewstate()
        {
            $viewstate =& $this->getElement('__VIEWSTATE');
            if (!is_array($this->_viewstate))
            {
                $this->_viewstate = array();
            }
            $viewstate->setValue(base64_encode(serialize($this->_viewstate)));
        }

        /**
         *
         * This function handles the action that would have been set client side in the hidden element
         * All it does is update the viewstate, as the rendering of the form is done elsewhere
         */
        function _actionHandler()
        {
            $actionElement =& $this->getElement('action');
            if (!$actionElement->getValue())
            {
                return true;
            }
            $action = $actionElement->getValue();
            $actionElement->setValue('');

            // actions look like 'profileAdd|something|somethingelse'
            $actions = explode('|',$action);
            switch ($actions[0])
            {
                case 'profileAdd':
                    // resets the addProfile box to the top element.
                    $selectBox =& $this->getElement('addProfile');
                    $selectBox->setValue(0);

                    if (!isset($this->_viewstate['profiles']))
                    {
                        $this->_viewstate['profiles'] = array();
                    }
                    if (!isset($this->_viewstate['profiles'][$actions[1]]))
                    {
                        $this->_viewstate['profiles'][$actions[1]] = array('checks' => array(), 'replys' => array());
                    }
                    break;
                case 'profileDel':
                    // resets the addProfile box to the top element.
                    $selectBox =& $this->getElement('addProfile');
                    $selectBox->setValue(0);
                    unset($this->_viewstate['profiles'][$actions[1]]);
                    break;
                case 'checkAdd':
                    if (!isset($this->_viewstate['profiles'][$actions[1]]['check']['elements']))
                    {
                        $this->_viewstate['profiles'][$actions[1]]['check']['elements'] = array();
                    }
                    array_push($this->_viewstate['profiles'][$actions[1]]['check']['elements'], $actions[2]);
                    break;
                case 'checkDelete':
                    unset($this->_viewstate['profiles'][$actions[1]]['check']['elements'][$actions[2]]);
                    break;
                case 'replyAdd':
                    if (!isset($this->_viewstate['profiles'][$actions[1]]['reply']['elements']))
                    {
                        $this->_viewstate['profiles'][$actions[1]]['reply']['elements'] = array();
                    }
                    array_push($this->_viewstate['profiles'][$actions[1]]['reply']['elements'], $actions[2]);
                    break;
                case 'replyDelete':
                    unset($this->_viewstate['profiles'][$actions[1]]['reply']['elements'][$actions[2]]);
                    break;
            }
            return true;
        }

        /**
         *
         * Returns a list of the profiles
         */
        function _getProfiles()
        {
            // will be read from a database soon
            return array(0 => 'LNS', 1 => 'LTS');
        }

        /**
         *
         * Returns a list of valid operators
         */
        function _getOperators()
        {
            return array('==' => '==',
                           '!=' => '!=',
                           '='  => '=',
                           ':=' => ':=',
                           '<=' => '<=',
                           '>=' => '>=',
                           '>'  => '>',
                           '<'  => '<',
                           '=~' => '=~',
                           '+=' => '+=',
                           '!~' => '!~',
                           '=*' => '=*',
                           '!*' => '!*'
                          );
        }

        /**
         *
         * Returns an array of groups from the database.
         */
        function _getGroups()
        {
            return array (1 => 'group a', 2 => 'group b');
        }

        /**
         *
         * Returns an array of checks
         */
        function _getChecks()
        {
            return array (1 => 'check 1', 2 => 'check 2');
        }

        /**
         *
         * Returns an array of replys
         */
        function _getReplies()
        {
            return array (1 => 'reply 1', 2 => 'reply 2');
        }
    }

?>
<script>
    function submitWithAction(action, selectBox)
    {
        var actionString;

        if (selectBox)
        {
            if (selectBox.selectedIndex == 0)
            {
                return false;
            }
            actionString = action + '|' + selectBox.options[selectBox.selectedIndex].text;
        }
        else
        {
            actionString = action;
        }

        document.RadUser.action.value = actionString;
        document.RadUser.submit();
    }
</script>

<h1>RADIUS User Admin (Expert)</h1>
<?php
    $form = new radForm();

    $form->display();

Irssi – making it beep when your nick is mentioned

Irssi by default will highlight your nickname, but that actually requires you to be looking at the screen. I wanted to make irssi beep when someone mentioned my nick, so that I didn’t have to actively monitor the tab in konsole. Here’s how to do it.

/set bell_beeps ON
/set beep_msg_level MSGS NOTICES DCC DCCMSGS HILIGHT