Thursday, April 7, 2016

Simple monitoring

I was searhing for a simple monitoring tool but most tools out there are very complex. We use 3rd party virtual private servers now so hardware monitoring is not our business. We're interested in monitoring two things:
  1. Free disk space
  2. CPU load
So I use two simple scripts that send out an e-mail alert when the diskspace is low or the CPU load it too high.

You can create the two scripts below and edit the MAILTO and TRIGGER variables to suit your needs /usr/local/bin/


host=`hostname -f`
load=`cat /proc/loadavg | awk '{print $2}'`
response=`echo | awk -v T=$TRIGGER -v L=$load 'BEGIN{if ( L > T){ print "greater"}}'`
if [[ $response = "greater" ]]
        #capture top command output for the mail body
        body=`top -n 1 -b`

        echo "$body\n."|mail -s "High load on $host - [ $load ]" $MAILTO


HOST=`hostname -f`
CURRENT=$(df / | grep / | awk '{ print $5}' | sed 's/%//g')

if [ "$CURRENT" -gt "$TRIGGER" ] ; then

    mail -s "Disk Space Alert for $HOST" $MAILTO << EOF
The root partition of '$HOST' remaining free space is critically low. Used: $CURRENT%

Make these two scripts executable:
chmod +x /usr/local/bin/ 
chmod +x /usr/local/bin/
Now schedule these script in system cron jobs:
# Check server load and diskspace
* * * * * root /usr/local/bin/
0 7,16 * * * root /usr/local/bin/
This will check the server load every minute and disk space at 7am and 4pm. Finally it's wise to test if mails sent from console arrive. Change the e-mail address in this command and run it:
echo "."|mail -s "Test mail from console"

Wednesday, May 13, 2015

DAVDroid calendar and contact sync

There's a very nice Android synchronization client called DAVDroid.
The beauty of this app is that the setup is extremely simple and sets up contact and calendar sync in one step. Here's a quick run through the setup:

1. Install the DAVDroid app and open it.
2. Select URL and user name:
3. Fill in your details:
4. Select the auto detected your address books and calendars you'd like to sync:

Now it's done and you can view the new calendars and address books in the calendar and contacts app!

Connect your website to Group-Office

Often it's desired to connect a website to Group-Office. For example you might want to have a sign up form that adds a contact to Group-Office.
Group-Office has a powerful JSON API to do this. Here's an example script that add's a contact using cURL. With cURL you can do HTTP requests in your own PHP script that you can run on your own CMS like Wordpress or Drupal for example.

//URL to Group-Office. You must use SSL because we use basic auth!
$groupoffice_url = "https://localhost/groupoffice-6.1/www/";

//Group-Office username and password. You should create a restricted user that 
//can only add contacts to this addressbook.
$username = 'website';
$password = 'secret';

//The contact properties to POST
$post = array(
  'addressbook_id' => 1, //required
  'company_id' => 0,
  'first_name' => 'Curl',
  'last_name' => 'Tester',
  'initials' => '',
  'title' => '',
  'suffix' => '',
  'sex' => 'M', // or 'F"
  'birthday' => '', //local format
   'email' => '',
  'email2' => '',
  'email3' => '',
  'department' => '',
  'function' => '',
  'home_phone' => '',
  'work_phone' => '',
  'fax' => '',
  'work_fax' => '',
  'cellular' => '',
  'cellular2' => '',
  'homepage' => '',
  'country' => 'NL', //2 character ISO code 
  'state' => '',
  'city' => '',
  'zip' => '',
  'address' => '',
  'address_no' => '',
  'comment' => ''

$process = curl_init($groupoffice_url . '?r=addressbook/contact/submit');
curl_setopt($process, CURLOPT_USERPWD, $username . ":" . $password);
curl_setopt($process, CURLOPT_POST, 1);
curl_setopt($process, CURLOPT_POSTFIELDS, $post);
curl_setopt($process, CURLOPT_RETURNTRANSFER, TRUE);

$return = curl_exec($process);

//JSON decode the response
$json = json_decode($return, true);

//Handle success or error here.
if ($json['success']) {
 echo "Contact saved!\n";
} else {
 echo "Failed to save contact: " . $json['feedback'] . "\n";

Tuesday, October 21, 2014

Anti spam plugin

When hosting e-mail, you'll have to deal with spam unfortunately. We use Amavis with spamassassin and ClamAV antivirus. This setup works great fo 95% of the time but there are always some spam messages that pass the spamfilter. For this you can train spamassassin to recognize the spam better.
I came across a nice dovecot plugin that is very simple to implement. Users can classify messages as spam simply by moving the messages into the spam folder. Taking messages out of the spam folder tells spamassassin that this message was in fact not spam.

Here's a short how to on the installation. I assume you have dovecot+spamasssin running already:

$ apt-get install dovecot-antispam

Add the "antispam" plugin to /etc/dovecot/conf.d/20-imap.conf (your plugins list may be different):

mail_plugins = $mail_plugins quota imap_quota antispam

Add the following to /etc/dovecot/conf.d/90-plugin.conf:

plugin {
  antispam_backend = pipe
  antispam_debug_target = syslog
  antispam_verbose_debug = 1
  antispam_signature= X-Spam-Status
  antispam_signature_missing= move
  antispam_mail_sendmail_args= --username=%u
  antispam_mail_spam  = --spam
  antispam_mail_notspam  = --ham
  antispam_mail_sendmail = /usr/bin/
  antispam_spam = SPAM;Spam
  antispam_unsure = Virus
  antispam_trash = Trash;trash

Create /usr/bin/

echo /usr/bin/sa-learn $* /tmp/sendmail-msg-$$.txt
echo "$$-start ($*)" >> /tmp/sa-learn-pipe.log

#echo $* > /tmp/sendmail-parms.txt
cat<&0 >> /tmp/sendmail-msg-$$.txt

/usr/bin/sa-learn $* /tmp/sendmail-msg-$$.txt

rm -f /tmp/sendmail-msg-$$.txt

#echo "$$-end" >> /tmp/sa-learn-pipe.log

exit 0

Make this script executable
$ chmod +x /usr/bin/

Restart dovecot
$ service dovecot restart

Now move a message into the spam folder and watch /var/log/syslog. It should have something like this:
Oct 21 15:16:25 debian imap: antispam: mail copy: src spam: 0, dst spam: 1, src unsure: 0
Oct 21 15:16:25 debian imap: antispam: running mailtrain backend program /usr/bin/
Oct 21 15:16:25 debian imap: antispam: running mailtrain backend program /usr/bin/
Oct 21 15:16:25 debian imap: antispam: running mailtrain backend program parameter 1
Oct 21 15:16:25 debian imap: antispam: running mailtrain backend program parameter 2 --spam

After this test you should disable debugging in /etc/dovecot/conf.d/90-plugin.conf

Tuesday, August 12, 2014

Configuring a fresh Ubuntu for Group-Office development

Unfortunately my Asus Zenbook Prime's SSD drive failed so I had to install a fresh system for Group-Office development (twice...). I thought it would be useful to post my steps right after a fresh Ubuntu 14.04 installation:
  1. Install java for netbeans
     $ sudo add-apt-repository ppa:webupd8team/java
     $ sudo apt-get update
     $ sudo apt-get install oracle-java7-installer
  2. Install Netbeans from site.
     $ sh ~/Downloads/
  3. Install Group-Office
     $ sudo echo -e "\n## Group-Office repository\ndeb \ fivezero main" | sudo tee -a /etc/apt/sources.list
    $ gpg --keyserver hkp:// --recv-keys 01F1AE44 $ gpg --export --armor 01F1AE44 | sudo apt-key add - $ sudo apt-get update $ sudo apt-get install groupoffice-com
  4. Install subversion
     $ sudo apt-get install subversion
  5. Own the /var/www directory
     $ sudo chown -R mschering:mschering /var/www
  6. Checkout groupoffice repository
     $ svn co svn+ssh://
  7. Launch Netbeans and open the Group-Office project and start coding.
  8. Install Firebug add-on in Firefox
  9. Install Dark look and feel plugin for Netbeans. I prefer a dark screen when staring at it for 8 hours a day ;)
  10. Install phpmyadmin
    $ sudo apt-get install phpmyadmin
    DANGER Set auto root login in /etc/phpmyadmin/config.php
        $cfg['Servers'][$i]['auth_type']    = 'config';
        $cfg['Servers'][$i]['user']         = 'root';  
        $cfg['Servers'][$i]['password']         = '';
        $cfg['Servers'][$i]['AllowNoPassword'] = TRUE;
  11. Disable local sending in SSH to get rid of warnings that locale is not found on remote server. Cange /etc/ssh/ssh_config:
    #    SendEnv LANG LC_*
  12. Install shutter for taking screenshots
    $ sudo apt-get install shutter

Some extra stuff for fun

  1. Install Variety for automatic wallpapers
     $ sudo add-apt-repository ppa:peterlevi/ppa
     $ sudo apt-get update
     $ sudo apt-get install variety
  2. Install Weather indicator
     $ sudo add-apt-repository ppa:atareao/atareao
     $ sudo apt-get update
     $ sudo apt-get install my-weather-indicator
  3. Mount WebDAV
     $ sudo apt-get install davfs2
    To enable webdav for non root users:
     $ sudo dpkg-reconfigure davfs2
     $ sudo vi /etc/fstab
    Add the line: /home/mschering/Group-Office davfs rw,user,noauto 0 0
    Add your user to the davfs2 group
     $ sudo adduser mschering davfs2
    Refresh your group membership without logging out:
     $ exec su -l mschering
    Create secrets file because it fails without:
     $ touch .davfs2/secrets
     $ chmod 600 .davfs2/secrets
    Create local dir:
     $ mkdir ~/Group-Office
     $ mount ~/Group-Office
  4. Install Skype I downloaded and installed Skype from their website which works fine except for the indicator icon. I had to install this package:
     $ sudo apt-get install sni-qt:i386

Thursday, July 24, 2014

New Intermesh frameworks

New technologies for the web are rising rapidly. As an application development company it's important to keep up with new technologies. I've explored and finally started to develop two frameworks that we will use for new applications.

On the server I want to create an API that's just communicating with clients through JSON requests. The server and client should be completely decoupled in my opinion. The server runs with the Intermesh PHP framework that features:
  • Api documentation with ApiGen
  • Model View Controller design pattern
  • ActiveRecord models for database ORM
  • Simple routing of HTTP requests to controller action methods
  • User authentication and role based permissions
  • Unit testing with phpunit
  • Composer support
On the client side I've developed an AngularJS framework for building an Angular client. The framework features:
  • API documentation with ngdocs
  • AngularJS uses the Model View Controller design pattern
  • bower support
  • services, directives and filters to communicate with the Intermesh PHP server API.
  • grunt to build the application, documentation and maintain index.html so it's not needed to add new scripts all the time.

Notes about the tools used


Composer is an essential tool. It takes care of:
  1. Installing and maintaining 3rd party libraries
  2. Autoloading PHP classes using the PSR-04 standard
There's no need to write your own autoloading script any more. Just install packages and you're good to go just by using the class names.


Documentation was always something that was pushed to a later date. So it's important to get this right at the start of a new project. I've tried various documentation generators PHPDoc, SAMI and ApiGen. The first two we're disappointing in the result. PHPDoc is more active and has more feature but the out of the box templates are just not good enough. ApiGen was the only one that produced a very usable result out of the box!


I think the only and best tool for unit testing. Works flawlessly out of the box.


An essential tool that is similar to Composer but for javascript packages.


Grunt is a javascript task runner. I used it for a couple of things. When I started with the AngularJS project I wanted to keep each component in a separate Javascript file to keep the code organized. Each time a new file was created I had to add it to the index.html file. As I'm a lazy programmer I don't like to do such annoying tasks :) Grunt can do that for me using the "fileblocks" module. Each time I add a file it's automatically inserted. Apart from that you also don't want to deploy your application like that. To improve performance grunt can concatenate and minify the Javascript, CSS and HTML for you.


Getting AngularJS documentation was tricky to setup. First of all there is some package confusion. I've tried ngdoc, ngdocs and dgeni. I couldn't get ngdoc to work at all so I moved on to ngdocs which worked well out of the box. I noticed the dgeni project is more active and used by AngularJS but it doesn't seem to be ready for community use yet. Perhaps it will grow out to be better than ngdocs.
The hardest thing to get going were the live inline examples. I used grunt to build a special script that includes all the Intermesh angular modules. With the "scripts" option for the ngdocs grunt task I was able to add those scripts to the docs so they started to work. See my Gruntfile.js for an example.
Here's an example of the ngdoc syntax for live examples:

Getting started

To get started with development you will need to install:
I use Ubuntu to develop on. If you want to install on Ubuntu you can install git and the Node Package Manager npm with this command:

$ sudo apt-get install git npm 

I had to work around some bug with (see

$ sudo ln -s /usr/bin/nodejs /usr/bin/node 

Install grunt, bower with the node package manager (use -g for global install):

$ sudo npm install -g grunt-cli bower

Install composer:

$ curl -sS | php 
$ sudo mv composer.phar /usr/local/bin/composer
Then install the server and client examples. Installation instructions are on the project pages on Github:


Wednesday, May 28, 2014

Building a Group-Office client with AngularJS and Bootstrap

To demonstrate how easy it is to build a client for Group-Office, I've created an AngularJS app. It demonstrates that the server side PHP code of Group-Office is in fact one big JSON API that can be talked to with a completely decoupled client.

It's a very simple interface that was just for a "Proof of concept" but here's a screenshot:

E-mail App in Angularjs Group-Office client

When we'll replace the current ExtJS 3 based user interface we'll use the same approach.

I've created a GitHub repository for the Group-Office client here:

Note that this client will only work with Group-Office 6.0.3 which you can get here:

I hope you like this example! You can also integrate these kind of API calls into your website or another application. Let me know what you think about it!


Note about CORS

If you run the Group-Office server on a different domain than this client you'll need to enable CORS. Otherwise you'll get errors like:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote
resource at http://localhost/groupoffice. This can be fixed by moving the resource
to the same domain or enabling CORS.

You can read more about enabling CORS on Group-Office here: