<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tony Bhimani's Blog &#187; HOWTOs</title>
	<atom:link href="http://www.tonybhimani.com/category/howtos/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.tonybhimani.com</link>
	<description>Where I Share my Linux and Programming Experiences</description>
	<lastBuildDate>Sun, 01 Jun 2008 02:48:34 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Creating Multi-Volume Archives and Checksums</title>
		<link>http://www.tonybhimani.com/2008/04/30/creating-multi-volume-archives-and-checksums/</link>
		<comments>http://www.tonybhimani.com/2008/04/30/creating-multi-volume-archives-and-checksums/#comments</comments>
		<pubDate>Thu, 01 May 2008 03:59:08 +0000</pubDate>
		<dc:creator>Tony</dc:creator>
				<category><![CDATA[HOWTOs]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[cat]]></category>
		<category><![CDATA[Checksum]]></category>
		<category><![CDATA[gzip]]></category>
		<category><![CDATA[md5sum]]></category>
		<category><![CDATA[Multi-Volume]]></category>
		<category><![CDATA[sha1sum]]></category>
		<category><![CDATA[split]]></category>
		<category><![CDATA[tar]]></category>
		<category><![CDATA[Volume Archive]]></category>

		<guid isPermaLink="false">http://www.tonybhimani.com/?p=27</guid>
		<description><![CDATA[The goal of this article is to help you create multi-volume archives and generate checksums to validate integrity. Why? You have data larger than any single CD-R disc or DVD and you need to split it into pieces, or you have to transfer gigabytes of data over the net and would rather send smaller segments [...]]]></description>
			<content:encoded><![CDATA[<p>The goal of this article is to help you create multi-volume archives and generate checksums to validate integrity. Why? You have data larger than any single CD-R disc or DVD and you need to split it into pieces, or you have to transfer gigabytes of data over the net and would rather send smaller segments instead of a giant glob. As an example, I&#8217;ll create a multi-volume gzip archive of /home with a MD5 checksum using tar, gzip, split, and md5sum.</p>
<h3>Creating Volumes from your Data</h3>
<p>1. Create a single TAR archive of all your data using tar to preserve permissions, directory structures, etc.</p>
<pre class="code">[root@linux archive]# tar -cf home.tar /home
tar: Removing leading `/' from member names
[root@linux archive]# ls -la home.tar
-rw-r--r-- 1 root root 304220160 Apr 30 13:34 home.tar</pre>
<p>2. Compress your TAR archive using gzip (or any other compressing program of your choice).</p>
<pre class="code">[root@linux archive]# gzip home.tar
[root@linux archive]# ls -la home.tar.gz
-rw-r--r-- 1 root root 284859091 Apr 30 13:34 home.tar.gz</pre>
<p>3. Use the split command to chop the compressed archive into smaller segments (I&#8217;ll be using 100MB pieces).</p>
<pre class="code">[root@linux archive]# split -d -b100m home.tar.gz home.tar.gz.
[root@linux archive]# ls -la
total 556940
drwxr-xr-x 2 root root      4096 Apr 30 13:56 .
drwxr-x--- 6 root root      4096 Apr 30 13:31 ..
-rw-r--r-- 1 root root 284859091 Apr 30 13:34 home.tar.gz
-rw-r--r-- 1 root root 104857600 Apr 30 13:56 home.tar.gz.00
-rw-r--r-- 1 root root 104857600 Apr 30 13:56 home.tar.gz.01
-rw-r--r-- 1 root root  75143891 Apr 30 13:57 home.tar.gz.02</pre>
<p>4. Create a MD5 checksum (or a SHA1 checksum).</p>
<pre class="code">[root@linux archive]# md5sum home.tar.gz* > MD5SUM
[root@linux archive]# cat MD5SUM
cb16175f4acad02f977f74d5c142879b  home.tar.gz
33c745ca49ab6e63b727658ec148cf67  home.tar.gz.00
14e6952b632fbb7f4c0731067afdb46c  home.tar.gz.01
386655357f8553c7730fd792c22fde2a  home.tar.gz.02</pre>
<p>Same thing but creating a SHA1 checksum instead (you don&#8217;t need two checksums, I just illustrate to use both types &#8212; pick one).</p>
<pre class="code">[root@linux archive]# sha1sum home.tar.gz* > SHA1SUM
[root@linux archive]# cat SHA1SUM
3858b51622dc9135c192a7c98dec24ccd35c63d6  home.tar.gz
6bc12b26dc1388d70d1a7cc0290dc6c9e8e0f97e  home.tar.gz.00
0683a44538ac65330fe103440e4f2a4a3a652be5  home.tar.gz.01
eb0f65fd0f4b3d98221e3ae8600f1691b536ad1d  home.tar.gz.02</pre>
<h3>Restoring your Data from the Volumes</h3>
<p>You&#8217;ve burned or transferred your volumes and now want to restore them to the original. Here are the steps.</p>
<p>1. Verify the checksum against the volumes (ignore the error on the original file).</p>
<pre class="code">[root@linux resurrection]# md5sum --check MD5SUM
md5sum: home.tar.gz: No such file or directory
home.tar.gz: FAILED open or read
home.tar.gz.00: OK
home.tar.gz.01: OK
home.tar.gz.02: OK
md5sum: WARNING: 1 of 4 listed files could not be read</pre>
<p>Once again, same deal but with the SHA1SUM file.</p>
<pre class="code">[root@linux resurrection]# sha1sum --check SHA1SUM
sha1sum: home.tar.gz: No such file or directory
home.tar.gz: FAILED open or read
home.tar.gz.00: OK
home.tar.gz.01: OK
home.tar.gz.02: OK
sha1sum: WARNING: 1 of 4 listed files could not be read</pre>
<p>2. Join the volume pieces together using cat (after you finish you can validate the checksum *again* to see if the original file passes an integrity check).</p>
<pre class="code">[root@node2 resurrection]# cat home.tar.gz.* > home.tar.gz
[root@node2 resurrection]# ls -la home.tar.gz
-rw-r--r-- 1 root root 284859091 Apr 30 15:23 home.tar.gz</pre>
<p>3. Decompress and extract the tar.gz file contents and you&#8217;re done.</p>
<pre class="code">[root@linux resurrection]# tar zxvf home.tar.gz
<em>... verbose file list ...</em>
[root@linux resurrection]# ls -la
total 556952
drwxr-xr-x 3 root root      4096 Apr 30 15:33 .
drwxr-x--- 7 root root      4096 Apr 30 15:02 ..
drwxr-xr-x 4 root root      4096 Apr 30 13:06 home
-rw-r--r-- 1 root root 284859091 Apr 30 15:23 home.tar.gz
-rw-r--r-- 1 root root 104857600 Apr 30 15:04 home.tar.gz.00
-rw-r--r-- 1 root root 104857600 Apr 30 15:04 home.tar.gz.01
-rw-r--r-- 1 root root  75143891 Apr 30 15:04 home.tar.gz.02
-rw-r--r-- 1 root root       193 Apr 30 15:05 MD5SUM
-rw-r--r-- 1 root root       225 Apr 30 15:05 SHA1SUM</pre>
<p>Contents extracted and there is the <em>home</em> directory. The End.</p>
<p>I got the idea of using the split command from this post on the <a href="http://ubuntuforums.org/showthread.php?t=455033" title="Ubuntu Forum (how to create multi zip files)">Ubuntu Forum (how to create multi zip files)</a> because I couldn&#8217;t get tar or gzip to create multi-volume archives.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tonybhimani.com/2008/04/30/creating-multi-volume-archives-and-checksums/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating Captcha Images with PHP and the GD Library</title>
		<link>http://www.tonybhimani.com/2008/02/01/creating-captcha-images-with-php-and-the-gd-library/</link>
		<comments>http://www.tonybhimani.com/2008/02/01/creating-captcha-images-with-php-and-the-gd-library/#comments</comments>
		<pubDate>Sat, 02 Feb 2008 06:34:01 +0000</pubDate>
		<dc:creator>Tony</dc:creator>
				<category><![CDATA[HOWTOs]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[captcha]]></category>
		<category><![CDATA[gd]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[security images]]></category>

		<guid isPermaLink="false">http://www.tonybhimani.com/2008/02/01/creating-captcha-images-with-php-and-the-gd-library/</guid>
		<description><![CDATA[A long time ago I wrote some code to create captcha images using PHP. The goal was to create similar or exact representations of the captcha&#8217;s used on Yahoo&#8217;s Overture. I really don&#8217;t have an answer why I chose their style except that it&#8217;s possible I liked the way they looked. I am sharing this [...]]]></description>
			<content:encoded><![CDATA[<p>A long time ago I wrote some code to create <a href="http://en.wikipedia.org/wiki/Captcha" title="Captcha definition on Wikipedia" target="_blank">captcha</a> images using PHP. The goal was to create similar or exact representations of the captcha&#8217;s used on Yahoo&#8217;s Overture. I really don&#8217;t have an answer why I chose their style except that it&#8217;s possible I liked the way they looked. I am sharing this code for creating the images but it&#8217;s up to you to create some logic in applying their use with HTML forms (I&#8217;ll give some hints at the end of this post).</p>
<p>This is the code to create the image. It returns an image resource identifier.  Note the use of a custom TrueType font &#8212;  you&#8217;ll need to change that line to the path of a font on your system.</p>
<pre class="code">&lt;?php
// generate captcha image - returns image handle
function captcha_image($code_string, $img_width=150, $img_height=40) {
  // seed srand
  srand((double)microtime()*1000000);

  // create image
  $im = @imagecreate($img_width, $img_height) or die("Cannot Initialize new GD image stream");

  // security code
  $security_code = $code_string;

  // define font
  $font = "/usr/fonts/ttf/Georgia.ttf";

  // create some colors
  $black = imagecolorallocate($im, 0, 0, 0);
  $white = imagecolorallocate($im, 255, 255, 255);
  $grey = imagecolorallocate($im, 128, 128, 128);

  // randomness, we need lots of randomness <img src='http://www.tonybhimani.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />
  // background color -&gt; 1=black, 2=white, 3=grey (more colors can be added)
  // lines -&gt; black bg (1=white or 2=grey), white bg (1=black or 2=grey), grey bg (black only)
  $randval = rand(1, 3);
  if ($randval == 1) {
    $bgcolor = $black;
    $fontcolor = $white;
    $linecolor = ((rand(0, 1) == 0) ? $black : $white);
  } elseif ($randval == 2) {
    $bgcolor = $white;
    $fontcolor = $black;
    $linecolor = ((rand(0, 1) == 0) ? $black : $white);
  } else {
    $bgcolor = $grey;
    $fontcolor = $black;
    $linecolor = ((rand(0, 1) == 0) ? $black : $grey);
  }

  // line positioning and increment
  $x_start = rand(0, 10);
  $x_size = rand(5, 10);
  $y_start = rand(0, 10);
  $y_size = rand(5, 10);

  // fill with background color
  imagefill($im, 0, 0, $bgcolor);

  // initial x position
  $font_x = 10;

  // write text
  for ($i = 0; $i &lt; strlen($security_code); $i++) {
    // font size -&gt; 20 to 35
    $font_size = rand(25, 35);
    // font angle -&gt; -20 to +20
    $font_angle = rand(0, 20);
    if ($font_angle != 0) { if (rand(0, 1) == 0) { $font_angle = -$fone_angle; } }
    // font y position -&gt; if font_size &lt;= 27 then 30 to 35, if font_size &gt; 27 then 30 to 35
    if ($font_size &lt;= 27) { $font_y = rand(25, 30); } else { $font_y = rand(30, 35); }
    // write the text
    imagettftext($im, $font_size, $font_angle, $font_x, $font_y, $fontcolor, $font, $security_code{$i});
    // one more time to make it bolder
    imagettftext($im, $font_size, $font_angle, $font_x+1, $font_y+1, $fontcolor, $font, $security_code{$i});
    // next font x position
    $font_x += ($font_size + 5);
  }

  // draw horizontal lines
  for ($y = $y_start; $y &lt; $img_height; $y += $y_size) {
    imageline($im, 0, $y, $img_width, $y, $linecolor);
  }
  // draw vertical lines
  for ($x = $x_start; $x &lt; $img_width; $x += $x_size) {
    imageline($im, $x, 0, $x, $img_height, $linecolor);
  }

  // return captcha image handle
  return $im;
}
?&gt;</pre>
<p>We need a method for generating random four character strings when the captcha is created and displayed to the user. This function will do the trick.</p>
<pre class="code">&lt;?php
function secret_key($length=4) {
  $salt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
  srand((double)microtime()*1000000);
  $i = 0;
  $skey = "";
  while ($i &lt; $length) {
    $num = rand() % strlen($salt);
    $tmp = substr($salt, $num, 1);
    $skey .= $tmp;
    $i++;
  }
  return $skey;
}
?&gt;</pre>
<p>With everything in place, we can generate the secret key, create the captcha, and finally display it to the user using this code.</p>
<pre class="code">&lt;?php
// set headers
header("Content-type: image/png");
header("Cache-Control: no-cache");
header("Pragma: no-cache");

// generate secret
$skey = secret_key();

// create captcha and output to browser as PNG image
$im = captcha_image($skey);
@imagepng($im);
@imagedestroy($im);
?&gt;</pre>
<p>Here is an example of the code in action. The style looks very similar to the images used on <a href="https://secure.overture.com/login.do" title="Yahoo's Overture" target="_blank">Yahoo&#8217;s Overture</a>.</p>
<p><strong><font size="+1">Captcha Demo »</font></strong>   <img src="http://www.tonybhimani.com/files/captcha/captcha.php" alt="Captcha" /></p>
<p>Now you know how to create a captcha, so what about verifying the input against the captcha value? This can be accomplished a variety of ways and everyone tends to have their preference.</p>
<ul>
<li>One method is to save the secret key in a session variable. As the image is created, store the key in a session variable and once the form is submitted, check the user&#8217;s value against the one stored in the session. If they match, proceed but if they fail, return an error and don&#8217;t process the form data.</li>
<li>If you don&#8217;t want to use sessions, you could try using temp files. Store the key in a temp file and pass some value as a query string identifying to the script that the key is in that file. Read in the key and <a href="http://www.php.net/manual/en/function.md5.php" title="PHP: md5 function reference" target="_blank">MD5</a> or <a href="http://www.php.net/manual/en/function.sha1.php" title="PHP: sha1 function reference" target="_blank">SHA1</a> crypt the key and save it in a hidden form field. When the form is submitted, compare the hashed key against the user input (which you will also hash). Process the form data if the keys match.</li>
</ul>
<p>You can download the provided source file. Use the PHP file as an image source in your HTML IMG tag.</p>
<pre class="code">&lt;img src="<span style="background-color: #ffff00">http://www.yourdomain.com/captcha.php</span>"&gt;</pre>
<p>Don&#8217;t forget to edit the path to the TrueType font you want to use in the <em>captcha_image</em> function. Failure to do so will lead to missing image characters.</p>
<p><strong>Source Files:</strong> <a href="http://www.tonybhimani.com/files/2008/02/captcha.zip" title="Captcha PHP Source Code">captcha.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.tonybhimani.com/2008/02/01/creating-captcha-images-with-php-and-the-gd-library/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Domain Redirection using Apache mod_rewrite and .htaccess</title>
		<link>http://www.tonybhimani.com/2008/01/26/domain-redirection-using-apache-mod_rewrite-and-htaccess/</link>
		<comments>http://www.tonybhimani.com/2008/01/26/domain-redirection-using-apache-mod_rewrite-and-htaccess/#comments</comments>
		<pubDate>Sun, 27 Jan 2008 04:21:49 +0000</pubDate>
		<dc:creator>Tony</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[BIND]]></category>
		<category><![CDATA[HOWTOs]]></category>
		<category><![CDATA[domain redirection]]></category>
		<category><![CDATA[htaccess]]></category>
		<category><![CDATA[mod_rewrite]]></category>
		<category><![CDATA[URL rewrite]]></category>

		<guid isPermaLink="false">http://www.tonybhimani.com/2008/01/26/domain-redirection-using-apache-mod_rewrite-and-htaccess/</guid>
		<description><![CDATA[I recently acquired more XenoCafe domains (xenocafe.info, xenocafe.net, and xenocafe.org) and finally got around to adding them to my server. Instead of them being their own sites (well, point to my primary site,  but the URL in the browser address bar is taken over by the new domain name), I wanted them to redirect [...]]]></description>
			<content:encoded><![CDATA[<p>I recently acquired more XenoCafe domains (<a href="http://xenocafe.info/" title="XenoCafe Linux Tutorials for Beginners" target="_blank">xenocafe.info</a>, <a href="http://xenocafe.net/" title="XenoCafe Linux Tutorials for Beginners" target="_blank">xenocafe.net</a>, and <a href="http://xenocafe.org/" title="XenoCafe Linux Tutorials for Beginners" target="_blank">xenocafe.org</a>) and finally got around to adding them to my server. Instead of them being their own sites (well, point to my primary site,  but the URL in the browser address bar is taken over by the new domain name), I wanted them to redirect to my primary domain (<a href="http://xenocafe.com/" title="XenoCafe Linux Tutorials for Beginners" target="_blank">xenocafe.com</a>).</p>
<p>If you want to achieve the same effect, here is how I did it (to see it in action, click on the first three XenoCafe links above). All you need is Apache, mod_rewrite, and htaccess. I&#8217;m going to skip the step-by-step configuration stuff to cut down the length of this article. If you need help, you can register for an account and post a question to the comments section for this post.</p>
<p>In this mock setup, I&#8217;ll use 10.10.100.34 as the IP address of my web server, example.com as the primary domain I want to redirect to, and ourexamples.com as the domain I want to redirect from (to example.com). This is a three step process that involves creating the zone file(s), adding the redirect domains to your Apache httpd.conf VirtualHost configuration, and finally creating the htaccess mod_rewrite rules to redirect all requests for the new domains to your desired domain.</p>
<p><strong>Create a New Zone File for each Domain you Acquired</strong></p>
<p>The primary domain example.com already has a zone file and is a functioning web site, but for ourexamples.com to work we need to create a zone file for it. Here is an example (we only need the minimum &#8211; SOA, NS, and the host for web).</p>
<pre class="code">$TTL   21600
$ORIGIN ourexamples.com.
@       IN      SOA     ns1.example.com. hostmaster.example.com. (
                        2008012601      ; serial
                        3600            ; refresh
                        600             ; retry
                        86400           ; expiry
                        21600 )         ; minimum

        IN      NS      ns1.example.com.
        IN      NS      ns2.example.com.

        IN      A       10.10.100.34
www     IN      A       10.10.100.34</pre>
<p>Now reload the zone(s) for changes to take effect.</p>
<p><strong>Add the Redirect Domains to the Primary Domain&#8217;s VirtualHost Definition (using the ServerAlias directive)</strong></p>
<p>Edit your primary domain&#8217;s virtual host entry and add the new domain(s) using the <a href="http://httpd.apache.org/docs/2.0/mod/core.html#serveralias" title="Apache ServerAlias Directive" target="_blank">ServerAlias</a> directive. Below is an example of editing the example.com virtual host and adding the new redirection domain ourexamples.com (highlighted line).</p>
<pre class="code">&lt;VirtualHost *:80&gt;
    ServerAdmin hostmaster@example.com
    ServerName example.com
    ServerAlias www.example.com
    <span style="background-color: #ffff00">ServerAlias ourexamples.com www.ourexamples.com</span>
    DocumentRoot /web/example/html
    ScriptAlias /cgi-bin/ /web/example/html/cgi-bin/
    ErrorLog /web/example/logs/error_log
    CustomLog /web/example/logs/access_log combined
    &lt;Directory "/web/example/html"&gt;
        AllowOverride All
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;</pre>
<p>Restart Apache to reload the virtual host changes. Next we&#8217;ll need to create the htaccess file to configure domain redirection.</p>
<p><strong>Using mod_rewrite to Redirect the Domain Requests</strong></p>
<p>If we were to stop here, the new domain would work, however there is no redirection to your primary domain name. It will simply use the same document root and serve the files without any changes to the URL in the browser address bar. If this is what you desire, then stop here, otherwise continue on to bounce all requests from ourexamples.com to example.com.</p>
<p>In the document root of where your HTML files are stored (where DocumentRoot points to in your Apache VirtualHost definition), create a .htaccess with a text editor. Here is the example.</p>
<pre class="code">&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
RewriteCond %{HTTP_HOST} !^$
RewriteRule (.*) http://www.example.com/$1 [L,R=301]
&lt;/IfModule&gt;</pre>
<p>In short, what this code does is turn on mod_rewrite&#8217;s engine, check the HTTP host to see if it matches www.example.com and also checks for empty references; if either case is a yes it rewrites the URL to http://www.example.com using a permanent redirect (HTTP 301 Redirection header). The $1 appends any portion trailing the domain name from the original (directories and/or pages being accessed). This code also forces the &#8216;www&#8217; prefix on all requests &#8212; <em>http://example.com </em>=&gt;<em> http://www.example.com</em> and <em>http://ourexamples.com </em>=&gt;<em> http://www.example.com</em> and so on</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tonybhimani.com/2008/01/26/domain-redirection-using-apache-mod_rewrite-and-htaccess/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Openfire Jabber/XMPP Server on CentOS mini-Howto</title>
		<link>http://www.tonybhimani.com/2007/12/31/openfire-jabberxmpp-server-on-centos-mini-howto/</link>
		<comments>http://www.tonybhimani.com/2007/12/31/openfire-jabberxmpp-server-on-centos-mini-howto/#comments</comments>
		<pubDate>Tue, 01 Jan 2008 06:13:38 +0000</pubDate>
		<dc:creator>Tony</dc:creator>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[HOWTOs]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[jabber]]></category>
		<category><![CDATA[openfire]]></category>
		<category><![CDATA[xmpp]]></category>

		<guid isPermaLink="false">http://www.tonybhimani.com/2007/12/31/openfire-jabberxmpp-server-on-centos-mini-howto/</guid>
		<description><![CDATA[So you want to set up your own private chat network for friends or family, or maybe your company uses the major chat providers like AIM, Yahoo, MSN, or Google for interoffice communication, but you want more control and to keep the network traffic inside your LAN. Whatever your case may be, this guide will [...]]]></description>
			<content:encoded><![CDATA[<p>So you want to set up your own private chat network for friends or family, or maybe your company uses the major chat providers like AIM, Yahoo, MSN, or Google for interoffice communication, but you want more control and to keep the network traffic inside your LAN. Whatever your case may be, this guide will show you how to do it with Ignite Realtime&#8217;s Openfire Jabber Server for Linux.</p>
<p><strong>Before we get started&#8230;</strong></p>
<p>There are two preliminary steps to complete before we install Openfire. They aren&#8217;t essential to its functionality (you can skip them if you&#8217;d like), but they&#8217;ll make things easier when it comes to managing the administration for you and your users. Those two steps are setting up a DNS alias for the server host name and creating a MySQL database for the backend instead of using the included embedded database.</p>
<p><strong>» Create a DNS Host Name for your Jabber Server</strong></p>
<p>For this guide I&#8217;ll use the host name &#8216;jabber&#8217; for my Openfire server. I run my own DNS server so I&#8217;ll be editing my zone file to add the new alias. If you use a third party service for DNS on your domain then you should know how to add new aliases. If you don&#8217;t then you should consult their Support documentation for more information.</p>
<p>Open your zone file in a text editor and add your new alias. Yours may look something like this example when you&#8217;re done. The highlighted line is what I added.</p>
<pre class="code">$TTL    21600
$ORIGIN mydomain.com.

@       IN      SOA     ns1.my-name-server.com. admin.my-name-server.com. (
                        2007122301      ; serial
                        3600            ; refresh
                        600             ; retry
                        86400           ; expiry
                        21600 )         ; minimum

                IN      NS      ns1.my-name-server.com.
                IN      NS      ns2.my-name-server.com.

                IN      MX      10      mx1.my-mail-server.com.
                IN      MX      20      mx2.my-mail-server.com.

                IN      A       10.0.0.100

www             IN      A       10.0.0.100
ftp             IN      A       10.0.0.100
<span style="background-color: #ffff00">jabber          IN      A       10.0.0.100</span></pre>
<p>Save your changes, flush the cache and reload the zone.</p>
<pre class="code">[root@node1 ~]# rndc flush
[root@node1 ~]# rndc reload</pre>
<p><strong>» Create the MySQL Database for Openfire Data</strong></p>
<p>Sometimes a tool like <a href="http://www.phpmyadmin.net/">phpMyAdmin</a> comes in handy for managing MySQL databases, however I don&#8217;t have it installed on this server. Instead I&#8217;ll be adding my Openfire database from the MySQL console. All we need to do is create the database, add an user account that has full control over that database, and reload (flush) the privileges.</p>
<pre class="code">[root@node1 ~]# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 3 to server version: 5.0.22

Type 'help;' or 'h' for help. Type 'c' to clear the buffer.

mysql&gt; CREATE DATABASE `openfire`;
Query OK, 1 row affected (0.00 sec)

mysql&gt; CREATE USER 'openfire'@'localhost' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.01 sec)

mysql&gt; GRANT USAGE ON *.* TO 'openfire'@'localhost' IDENTIFIED BY 'password' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;
Query OK, 0 rows affected (0.00 sec)

mysql&gt; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES ON `openfire`.* TO 'openfire'@'localhost';
Query OK, 0 rows affected (0.01 sec)

mysql&gt; FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.02 sec)

mysql&gt; quit
Bye
[root@node1 ~]#</pre>
<p>Now that all the preliminaries are out of the way, we can move onto installing Openfire.</p>
<p><strong>Download and Install the Openfire Software</strong></p>
<p>Openfire can be downloaded from the <a href="http://www.igniterealtime.org/">Ignite Realtime</a> web site. As of this writing, the latest version available for download is <a href="http://www.igniterealtime.org/downloadServlet?filename=openfire/openfire-3.4.2-1.i386.rpm">Openfire 3.4.2 for Linux</a>.</p>
<p>We&#8217;ll start by downloading the Openfire RPM via wget.</p>
<pre class="code">[root@node1 ~]# wget -O openfire-3.4.2-1.i386.rpm http://www.igniterealtime.org/downloadServlet?filename=openfire/openfire-3.4.2-1.i386.rpm
--12:18:13-- http://www.igniterealtime.org/downloadServlet?filename=openfire/openfire-3.4.2-1.i386.rpm
Resolving www.igniterealtime.org... 63.246.20.125
Connecting to www.igniterealtime.org|63.246.20.125|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 40451331 (39M) [application/x-rpm]
Saving to: `openfire-3.4.2-1.i386.rpm'

100%[=====================================================================&gt;] 40,451,331   368K/s   in 1m 52s

12:20:05 (354 KB/s) - `openfire-3.4.2-1.i386.rpm' saved [40451331/40451331]

[root@node1 ~]#</pre>
<p>Now install the RPM, start the Openfire service, verify it is actively running, and set it to auto-start whenever your server is rebooted.</p>
<pre class="code">[root@node1 ~]# rpm -ivh openfire-3.4.2-1.i386.rpm
Preparing...                ########################################### [100%]
   1:openfire               ########################################### [100%]
[root@node1 ~]# /etc/init.d/openfire start
Starting openfire:
[root@node1 ~]# ps -ef | grep -i openfire
root      2508     1  0 07:35 pts/0    00:00:00 su -s /bin/sh -c /opt/openfire/jre/bin/java -server  -DopenfireHome=/opt/openfire -Dopenfire.lib.dir=/opt/openfire/lib -classpath "/opt/openfire/lib/startup.jar" -jar "/opt/openfire/lib/startup.jar" daemon
daemon    2511  2508 37 07:35 ?        00:00:07 /opt/openfire/jre/bin/java -server -DopenfireHome=/opt/openfire -Dopenfire.lib.dir=/opt/openfire/lib -classpath /opt/openfire/lib/startup.jar -jar /opt/openfire/lib/startup.jar
root      2526  2414  1 07:35 pts/0    00:00:00 grep -i openfire
[root@node1 ~]# chkconfig --level 235 openfire on
[root@node1 ~]#</pre>
<p><strong>Open Ports in your Firewall</strong></p>
<p>If you have a firewall in place you&#8217;ll need to open some ports before we can start configuring Openfire through its web interface. Openfire uses ports 5222, 7777, 9090, 9091 for client connections, file transfer proxy, http web administration and the secured administration respectively. If you use iptables tables like I do, add these lines to your <em>/etc/sysconfig/iptables</em> rules file and reload. See my <a href="http://www.xenocafe.com/tutorials/linux/redhat/iptables/iptables_linux_redhat-part1.php" title="RedHat IPTables Tutorial on XenoCafe" target="_blank">RedHat IPTables Tutorial on XenoCafe</a> for more information on configuring iptables from the ground up.</p>
<pre class="code">-A INPUT -p tcp -i eth0 --dport 5222 -j ACCEPT
-A INPUT -p udp -i eth0 --dport 5222 -j ACCEPT
-A INPUT -p tcp -i eth0 --dport 7777 -j ACCEPT
-A INPUT -p udp -i eth0 --dport 7777 -j ACCEPT
-A INPUT -p tcp -i eth0 --dport 9090 -j ACCEPT
-A INPUT -p udp -i eth0 --dport 9090 -j ACCEPT
-A INPUT -p tcp -i eth0 --dport 9091 -j ACCEPT
-A INPUT -p udp -i eth0 --dport 9091 -j ACCEPT</pre>
<p>Then reload iptables to accept the new directives.</p>
<pre class="code">[root@node1 ~]# iptables-restore &lt; /etc/sysconfig/iptables</pre>
<p><strong>Configure Openfire through its Web Interface</strong></p>
<p>1. Launch your favorite browser and go to <em>http://your_jabber_server_ip_address:9090</em> or if you set up a DNS alias <em>http://jabber.mydomain.com:9090</em> to go to the Openfire web interface. You&#8217;ll be greeted by Openfire&#8217;s setup tool. In the first step, select your language. Here we choose English.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/language.jpg" title="Openfire Setup: Language Selection Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_language.jpg" alt="Openfire Setup: Language Selection Screen" border="0" height="261" width="425" /></a></p>
<p>2. The next step is to set the server domain. If you opted for an IP address name, enter your server&#8217;s IP. If you opted to create a DNS alias, enter the DNS server domain. Here we created jabber.mydomain.com so we&#8217;ll enter that. By default the Openfire web interface console ports are 9090 and 9091 for standard and secure respectively. You can use other ports if you wish (NOTE: you&#8217;ll have to change your firewall settings if you use different ports), but for this guide we&#8217;re sticking with the default values.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/server.jpg" title="Openfire Setup: Server Settings Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_server.jpg" alt="Openfire Setup: Server Settings Screen" border="0" height="187" width="425" /></a></p>
<p>3. You have two choices regarding which database to use for Openfire to store its data: an external database like MySQL, MSSQL, PostgreSQL, etc&#8230; or to use the bundled embedded database. If you setup a MySQL database like we did in this guide then select the Standard Database Connection option. If you didn&#8217;t, the only choice is to use the Embedded Database.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/database.jpg" title="Openfire Setup: Language Selection Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_database.jpg" alt="Openfire Setup: Database Settings Screen" border="0" height="200" width="425" /></a></p>
<p>4. To set up your database connection, select the appropriate driver from the Database Driver Presets list (we set up a MySQL database so we&#8217;ll select MySQL). The page will refresh and you need to fill in the necessary information (the database host, name, username, and password). You should have this information from when you setup your MySQL database. Per this guide, MySQL is on the same server as my Openfire installation (localhost) and I created a database called &#8216;openfire&#8217; with a username of &#8216;openfire&#8217; and set a password.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/dbsettings.jpg" title="Openfire Setup: Database Settings Configuration Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_dbsettings.jpg" alt="Openfire Setup: Database Settings Configuration Screen" border="0" height="319" width="425" /></a></p>
<p>5. The profile step has to do with the users and groups of chat members and where Openfire will store that information (new users, user groups, etc&#8230;). We won&#8217;t opt for LDAP to store this information. It is much more convenient to save it in our in our database.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/profile.jpg" title="Openfire Setup: Profile Settings Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_profile.jpg" alt="Openfire Setup: Profile Settings Configuration Screen" border="0" height="187" width="425" /></a></p>
<p>6. We&#8217;re almost done. Enter the administrator email address (your email address) and set a password for your Openfire server.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/admin.jpg" title="Openfire Setup: Admin Account Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_admin.jpg" alt="Openfire Setup: Admin Account Screen" border="0" height="204" width="425" /></a></p>
<p>7. Now you&#8217;re done! Pat yourself on the back. Click the <strong>Login to admin console</strong> button.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/setupcomplete.jpg" title="Openfire Setup: Setup Complete Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_setupcomplete.jpg" alt="Openfire Setup: Setup Complete Screen" border="0" height="276" width="425" /></a></p>
<p>8. Type in the Openfire admin password you entered in Step 6 and click the <strong>Login</strong> button.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/login.jpg" title="Openfire Setup: Admin Login Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_login.jpg" alt="Openfire Setup: Admin Login Screen" border="0" height="274" width="425" /></a></p>
<p>Welcome to the Openfire Administration Console. Take a look around and get familiar with the layout.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/console.jpg" title="Openfire: Administration Console Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_console.jpg" alt="Openfire: Administration Console Screen" border="0" height="309" width="425" /></a></p>
<p><strong>Time to Make Some Openfire Configuration Changes</strong></p>
<p>Your Openfire installation will work out of the box and you can skip this section if you want, but for this tutorial I wanted to make some changes. Namely, I want my server to follow some rules so there is no chaos.</p>
<ol>
<li>I don&#8217;t want any other servers to be able to communicate with mine (it&#8217;s private and self sufficient)</li>
<li>I define the member base so anonymous users cannot create accounts (ideal for an office environment)</li>
<li>Finally, all communication between clients and the server is encrypted (force jabber clients to use SSL)</li>
</ol>
<p>Follow along if you want to use any of these features or jump ahead to the <a href="#cugjc" title="Creating Users and Groups for Jabber Clients">Creating Users and Groups for Jabber Clients</a> section.</p>
<p>1. On the left under <strong>Server Settings</strong>, click the <strong>Server to Server</strong> link. In the top panel <strong>Service Enabled</strong>, choose the <strong>Disabled</strong> option and click <strong>Save Settings</strong>.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/srv2srv.jpg" title="Openfire: Administration Console 'Server to Server' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_srv2srv.jpg" alt="Openfire: Administration Console 'Server to Server' Screen" border="0" height="191" width="425" /></a></p>
<p>2. Click the <strong>Registration &amp; Login</strong> link in the left side menu. Disable both options under <strong>Inband Account Registration</strong> and <strong>Anonymous Login</strong>. We&#8217;ll leave the <strong>Change Password</strong> option alone to let users update their passwords as they see fit. Click the <strong>Save Settings</strong> button at the bottom of the page.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/reglogin.jpg" title="Openfire: Administration Console 'Registration &amp; Login' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_reglogin.jpg" alt="Openfire: Administration Console 'Registration &amp; Login' Screen" border="0" height="309" width="425" /></a></p>
<p>3. Click the <strong>Security Settings</strong> link on the left. Under <strong>Client Connection Security</strong>, choose the <strong>Required</strong> option to force jabber clients to use SSL (NOTE: If the client doesn&#8217;t support SSL and this option is enabled, the client will not be able to connect to the server). Click the <strong>Save Settings</strong> button.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/security.jpg" title="Openfire: Administration Console 'Security Settings' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_security.jpg" alt="Openfire: Administration Console 'Security Settings' Screen" border="0" height="277" width="425" /></a></p>
<p><strong>Openfire SSL Certificates</strong></p>
<p>Openfire creates self-signed SSL Certificates by default. Remember the port 9091 from before? If you ever want to access this administration console from a Secure Connection, then you&#8217;ll need to restart the Openfire HTTP Server.</p>
<p>Click the <strong>Server Certificates</strong> link on the left menu.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/sslcerts.jpg" title="Openfire: Administration Console 'Server Certificates' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_sslcerts.jpg" alt="Openfire: Administration Console 'Server Certificates' Screen" border="0" height="291" width="425" /></a></p>
<p>Click the link in the highlight section.</p>
<p><img src="http://www.tonybhimani.com/files/openfire_server/httprestart.jpg" alt="Openfire: HTTP Restart Link" border="0" height="20" width="425" /></p>
<p>Openfire will restart the HTTP Web Server and kick you back to the login screen. Log back in and the SSL Certificate should now be in use and you can access the console from SSL.</p>
<p><a title="cugjc" name="cugjc"></a><strong>Creating Users and Groups for Jabber Clients</strong></p>
<p>Since we&#8217;re creating a jabber server for a mock office environment, we prohibit anonymous users from creating accounts. Because of this, we will manage all users and groups on a global scale through our Openfire server. This means, all groups and users will be pushed to the clients that log in so they don&#8217;t have to add every single user account or group to their client. Also, any changes happen in real-time on the client (new users or groups added, removed, etc&#8230;). Kind of cool, huh? This is accomplished through Contact Group List Sharing.</p>
<p>We&#8217;ll be creating a mock Developer &#8220;Devel&#8221; group and add some users to it. Click on the <strong>Users/Groups</strong> tab on the top.</p>
<p>1. Go to <strong>Create New User</strong> under the <strong>Users</strong> section on the left. Fill in the <strong>Username</strong>, <strong>Password</strong>, and <strong>Confirm Password</strong>  fields and click the <strong>Create User</strong> button.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/newuser.jpg" title="Openfire: Administration Console 'Create New User' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_newuser.jpg" alt="Openfire: Administration Console 'Create New User' Screen" border="0" height="292" width="425" /></a></p>
<p>Repeat this process to add all the users you want on your server.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/userprops.jpg" title="Openfire: Administration Console 'User Properties' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_userprops.jpg" alt="Openfire: Administration Console 'User Properties' Screen" border="0" height="344" width="425" /></a></p>
<p>2. Go to <strong>Create New Group</strong> under the <strong>Groups</strong> section on the left. Fill in the <strong>Group Name</strong> and an optional <strong>Description</strong>. Click the <strong>Create Group</strong> button.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/newgroup.jpg" title="Openfire: Administration Console 'Create Group' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_newgroup.jpg" alt="Openfire: Administration Console 'Create Group' Screen" border="0" height="283" width="425" /></a></p>
<p>3. The group has been added. Now we&#8217;ll share the contact list so it&#8217;s global to all jabber clients that connect to our server. Under the <strong>Contact List (Roster) Sharing</strong> section, click the <strong>Enable contact list group sharing</strong> option. In the name field, type in the same name as set for the group. Click the <strong>Save Contact List Settings</strong> button.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/editgroup.jpg" title="Openfire: Administration Console 'Edit Group' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_editgroup.jpg" alt="Openfire: Administration Console 'Edit Group' Screen" border="0" height="261" width="425" /></a></p>
<p>4. Scroll down the page and type in an user name to the <strong>Add User</strong> field and click the <strong>Add</strong> button.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/addmembers.jpg" title="Openfire: Administration Console 'Members of This Group' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_addmembers.jpg" alt="Openfire: Administration Console 'Members of This Group' Screen" border="0" height="110" width="425" /></a></p>
<p>Now we have one member in our group. Repeat this for each user you want assigned to this group.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/groupmembers.jpg" title="Openfire: Administration Console 'Members of This Group' Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_groupmembers.jpg" alt="Openfire: Administration Console 'Members of This Group' Screen" border="0" height="107" width="425" /></a></p>
<p><strong>Setting up a Jabber Client (Spark 2.5.8 for Windows)</strong></p>
<p>Our Openfire Jabber Server is useless unless we have clients connect to it and communicate through it. We&#8217;ll use <a href="http://www.igniterealtime.org/downloads/index.jsp" title="Spark Jabber Client" target="_blank">Spark </a>from Ignite Realtime. If that doesn&#8217;t suit you then you are open to use another jabber client since there are many of them out there (<a href="http://www.jabber.org/software/clients.shtml" title="Jabber Clients" target="_blank">see the client from jabber.org</a>).</p>
<p>1. Download <a href="http://www.igniterealtime.org/downloadServlet?filename=spark/spark_2_5_8.exe" title="Download Spark 2.5.8 for Windows">Spark</a>, install it, and launch it.</p>
<p>2. Type in your Openfire user credentials (<strong>Username</strong> and <strong>Password</strong>). In the <strong>Server</strong> field, type in the Openfire Servers IP address or DNS alias. Click the <strong>Login</strong> button.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/clientlogin.jpg" title="Spark: Client Login Screen" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_clientlogin.jpg" alt="Spark: Client Login Screen" border="0" height="348" width="425" /></a></p>
<p>3. The contact list will appear once you have successfully logged in. The shared group(s) will be visible (NOTE: groups with no online users will be hidden unless you select the <strong>Show empty groups</strong> option from the <strong>Contacts</strong> menu) along with the users of those groups. My contacts are not online as you can see from the picture below.</p>
<p><a href="http://www.tonybhimani.com/files/openfire_server/spark.jpg" title="Spark: Contact List Window" target="_blank"><img src="http://www.tonybhimani.com/files/openfire_server/small_spark.jpg" alt="Spark: Contact List Window" border="0" height="400" width="187" /></a></p>
<p>You&#8217;re done. You now have the essentials of configuring your own Jabber server and clients.</p>
<p>This is my last tutorial, guide, howto, whatever you want to call it for 2007. Happy New Year!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tonybhimani.com/2007/12/31/openfire-jabberxmpp-server-on-centos-mini-howto/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>CentOS 5.1 Network Install Instructions</title>
		<link>http://www.tonybhimani.com/2007/12/20/centos-51-network-install-instructions/</link>
		<comments>http://www.tonybhimani.com/2007/12/20/centos-51-network-install-instructions/#comments</comments>
		<pubDate>Fri, 21 Dec 2007 05:56:08 +0000</pubDate>
		<dc:creator>Tony</dc:creator>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[HOWTOs]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.tonybhimani.com/2007/12/20/centos-51-network-install-instructions/</guid>
		<description><![CDATA[This is a simple guide to installing CentOS 5.1 via Network Install (netinstall). You can save yourself a lot of time by doing a network install and only installing the base packages rather than downloading a 3.6GB DVD ISO or the six CD-ROM images.
1. Start by downloading the small 7.3MB CentOS-5.1-i386-netinstall.iso image and burn it [...]]]></description>
			<content:encoded><![CDATA[<p>This is a simple guide to installing CentOS 5.1 via Network Install (netinstall). You can save yourself a lot of time by doing a network install and only installing the base packages rather than downloading a 3.6GB DVD ISO or the six CD-ROM images.</p>
<p>1. Start by downloading the small 7.3MB <a href="http://mirrors.kernel.org/centos/5.1/isos/i386/CentOS-5.1-i386-netinstall.iso">CentOS-5.1-i386-netinstall.iso</a> image and burn it to a disc. There&#8217;s also an x86_64 architecture image available that you can <a href="http://mirrors.kernel.org/centos/5.1/isos/x86_64/CentOS-5.1-x86_64-netinstall.iso">download</a> if that&#8217;s the type of hardware you&#8217;re using.</p>
<p>2. Boot up the designated CentOS PC with your netinstall disc and wait for it to get to boot screen.</p>
<p><a href="http://www.tonybhimani.com/files/centos_netinstall/boot.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/centos_netinstall/small_boot.jpg" title="CentOS 5.1 Network Install Boot Screen" alt="CentOS 5.1 Network Install Boot Screen" border="0" height="319" width="425" /></a></p>
<p>Press <em>Enter</em> for the GUI install or type  <strong>linux text</strong> and press <em>Enter</em> for text mode installation.</p>
<p>3. Choose your language. The default selection is English.</p>
<p><a href="http://www.tonybhimani.com/files/centos_netinstall/language.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/centos_netinstall/small_language.jpg" title="CentOS 5.1 Network Install Language Screen" alt="CentOS 5.1 Network Install Language Screen" border="0" height="266" width="425" /></a></p>
<p>Is English your primary language? It is for me.</p>
<p>4. Choose your keyboard type. The default is a US keyboard layout.</p>
<p><a href="http://www.tonybhimani.com/files/centos_netinstall/keyboard.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/centos_netinstall/small_keyboard.jpg" title="CentOS 5.1 Network Install Keyboard Type Screen" alt="CentOS 5.1 Network Install Keyboard Type Screen" border="0" height="266" width="425" /></a></p>
<p>My keyboard is as basic as they come. So I&#8217;m choosing US.</p>
<p>5. Choose the installation method. For this guide I perform a HTTP install and get the packages from <a href="http://www.kernel.org/">kernel.org</a>.</p>
<p><a href="http://www.tonybhimani.com/files/centos_netinstall/installmethod.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/centos_netinstall/small_installmethod.jpg" title="CentOS 5.1 Network Install Installation Method Screen" alt="CentOS 5.1 Network Install Installation Method Screen" border="0" height="266" width="425" /></a></p>
<p>6. Now it&#8217;s time to configure the TCP/IP settings. If you want to acquire an IP from a DHCP server or have no idea what your network settings are, then leave everything on the defaults. However, if you want to use a static IP and save yourself the trouble of editing <strong>/etc/sysconfig/network-scripts/ifcfg-eth0</strong> or running <strong>setup</strong> later, then choose <strong>Manual configuration</strong>. I don&#8217;t have an IPv6 network, so I&#8217;ll be using IPv4.</p>
<p><a href="http://www.tonybhimani.com/files/centos_netinstall/tcpip.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/centos_netinstall/small_tcpip.jpg" title="CentOS 5.1 Network Install Configure TCP/IP Screen" alt="CentOS 5.1 Network Install Configure TCP/IP Screen" border="0" height="266" width="425" /></a></p>
<p>7. Skip this step if you chose DHCP. On this screen enter your network settings (IP address, subnet mask, default gateway, and a dns name server).</p>
<p><a href="http://www.tonybhimani.com/files/centos_netinstall/tcpip2.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/centos_netinstall/small_tcpip2.jpg" title="CentOS 5.1 Network Install Manual TCP/IP Configuration Screen" alt="CentOS 5.1 Network Install Manual TCP/IP Configuration Screen" border="0" height="266" width="425" /></a></p>
<p>8. Enter the web server and directory path to the CentOS packages to get this installation started. I&#8217;ll be using the server mirrors.kernel.org. The directory path is centos/5.1/os/i386.</p>
<p><a href="http://www.tonybhimani.com/files/centos_netinstall/httpsetup.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/centos_netinstall/small_httpsetup.jpg" title="CentOS 5.1 Network Install HTTP Setup Screen" alt="CentOS 5.1 Network Install HTTP Setup Screen" border="0" height="266" width="425" /></a></p>
<p>9. Go get something to drink. Retrieving the image may take a while.</p>
<p><a href="http://www.tonybhimani.com/files/centos_netinstall/retrieving.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/centos_netinstall/small_retrieving.jpg" title="CentOS 5.1 Network Install Retrieving Image Screen" alt="CentOS 5.1 Network Install Retrieving Image Screen" border="0" height="266" width="425" /></a></p>
<p>10. Follow the rest of the prompts to install CentOS. It&#8217;s the same as if you&#8217;re doing it from DVD or CD&#8217;s, just takes longer because all packages are downloaded. So select your packages, set the root password, etc&#8230; The installation time will depend on how many packages you select.</p>
<p><a href="http://www.tonybhimani.com/files/centos_netinstall/welcome.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/centos_netinstall/small_welcome.jpg" title="CentOS 5.1 Network Install Welcome to CentOS Screen" alt="CentOS 5.1 Network Install Welcome to CentOS Screen" border="0" height="266" width="425" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.tonybhimani.com/2007/12/20/centos-51-network-install-instructions/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Searching for fields in unknown MySQL tables</title>
		<link>http://www.tonybhimani.com/2007/11/02/searching-for-fields-in-unknown-mysql-tables/</link>
		<comments>http://www.tonybhimani.com/2007/11/02/searching-for-fields-in-unknown-mysql-tables/#comments</comments>
		<pubDate>Sat, 03 Nov 2007 03:28:20 +0000</pubDate>
		<dc:creator>Tony</dc:creator>
				<category><![CDATA[HOWTOs]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.tonybhimani.com/2007/11/02/searching-for-fields-in-unknown-mysql-tables/</guid>
		<description><![CDATA[A friend emailed me weeks ago asking if there is a SQL SELECT statement to search for fields in a database if the table names are unknown. As far as I knew there wasn&#8217;t and suggested creating a script to do the searching for her.
1. Here&#8217;s a code snippet to achieve a search for a [...]]]></description>
			<content:encoded><![CDATA[<p>A friend emailed me weeks ago asking if there is a SQL SELECT statement to search for fields in a database if the table names are unknown. As far as I knew there wasn&#8217;t and suggested creating a script to do the searching for her.</p>
<p>1. Here&#8217;s a code snippet to achieve a search for a single field across all tables in a specified database.</p>
<pre class="code">&lt;?php
// variables
$dbname = 'my_db';
$dbfield = 'my_field';
// connect to database
$dblink = mysql_connect('localhost', 'user', 'password');
if ($dblink) {
  mysql_select_db($dbname, $dblink);
} else {
  die('Failed to connect to DB');
}
// get table list
$query = "show tables";
$result = mysql_query($query, $dblink);
// loop through table names
while (list($table) =  mysql_fetch_row($result)) {
  // get table description
  $query = "describe $table";
  $result2 = mysql_query($query, $dblink);
  // loop through table description fields
  while ($row = mysql_fetch_array($result2, MYSQL_ASSOC)) {
    // does this field match what we're looking for?
    if ($row['Field'] == $dbfield) {
      echo "Found '".$row['Field']."' in table =&gt; $table&#92;n";
    }
  }
  mysql_free_result($result2);
}
mysql_free_result($result);
?&gt;</pre>
<p>2. This is a variant to achieve a search for an array of fields across all tables in a specified database.</p>
<pre class="code">&lt;?php
// variables
$dbname = 'my_db';
$dbfields = array('my_field1','my_field2','my_field3');
// connect to database
$dblink = mysql_connect('localhost', 'user', 'password');
if ($dblink) {
  mysql_select_db($dbname, $dblink);
} else {
  die('Failed to connect to DB');
}
// get table list
$query = "show tables";
$result = mysql_query($query, $dblink);
// loop through table names
while (list($table) =  mysql_fetch_row($result)) {
  // get table description
  $query = "describe $table";
  $result2 = mysql_query($query, $dblink);
  // loop through table description fields
  while ($row = mysql_fetch_array($result2, MYSQL_ASSOC)) {
    // does this field match any in the array?
    if (in_array($row['Field'], $dbfields)) {
      echo "Found '".$row['Field']."' in table =&gt; $table&#92;n";
    }
  }
  mysql_free_result($result2);
}
mysql_free_result($result);
?&gt;</pre>
<p>3. And finally, this version searches for an array of fields across all tables and databases in MySQL.</p>
<pre class="code">&lt;?php
// variables
$dbfields = array('my_field1','my_field2','my_field3');
// connect to database
$dblink = mysql_connect('localhost', 'user', 'password');
if (!$dblink) {
  die('Failed to connect to DB');
}
// get databases list
$query = "show databases";
$result = mysql_query($query, $dblink);
// loop through table names
while (list($dbname) =  mysql_fetch_row($result)) {
  mysql_select_db($dbname);
  // get table list
  $query = "show tables";
  $result2 = mysql_query($query, $dblink);
  // loop through table names
  while (list($table) =  mysql_fetch_row($result2)) {
    // get table description
    $query = "describe $table";
    $result3 = mysql_query($query, $dblink);
    // loop through table description fields
    while ($row = mysql_fetch_array($result3, MYSQL_ASSOC)) {
      // does this field match what we're looking for?
      if (in_array($row['Field'], $dbfields)) {
        echo "Found '".$row['Field']."' in table =&gt; $table of database =&gt; $dbname&#92;n";
      }
    }
    mysql_free_result($result3);
  }
  mysql_free_result($result2);
}
mysql_free_result($result);
?&gt;</pre>
<p>Be sure to change the variables $dbname, $dbfields, and the mysql_connect options before using these scripts. You can run them by typing</p>
<pre class="code">php -f /path/filename</pre>
<p>on the command-line or from your web server. If run from the web, change the new line (&#92;n) to a HTML line break (&lt;br&gt;).</p>
<p><strong>Source Files:</strong> <a href="http://www.tonybhimani.com/files/2007/11/db-search-fields.zip">db-search-fields.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.tonybhimani.com/2007/11/02/searching-for-fields-in-unknown-mysql-tables/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hotlink Protection with Apache mod_rewrite and .htaccess</title>
		<link>http://www.tonybhimani.com/2007/11/02/hotlink-protection-with-apache-mod_rewrite-and-htaccess/</link>
		<comments>http://www.tonybhimani.com/2007/11/02/hotlink-protection-with-apache-mod_rewrite-and-htaccess/#comments</comments>
		<pubDate>Fri, 02 Nov 2007 17:39:46 +0000</pubDate>
		<dc:creator>Tony</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[HOWTOs]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.tonybhimani.com/2007/11/02/hotlink-protection-with-apache-mod_rewrite-and-htaccess/</guid>
		<description><![CDATA[So you have people linking to files on your site and it&#8217;s eating up all your bandwidth. You want it to stop but you&#8217;re not sure how. If you&#8217;re using Apache for your web server, you can use .htaccess to block the file requests from remote servers and put an end to your bandwidth theft.
I&#8217;m [...]]]></description>
			<content:encoded><![CDATA[<p>So you have people linking to files on your site and it&#8217;s eating up all your bandwidth. You want it to stop but you&#8217;re not sure how. If you&#8217;re using Apache for your web server, you can use .htaccess to block the file requests from remote servers and put an end to your bandwidth theft.</p>
<p>I&#8217;m writing this article because I&#8217;m a victim of people placing links to my images on their site&#8217;s without my permission, slowly eating away at the bandwidth I&#8217;m paying for, not them. If you&#8217;re reading this, it&#8217;s likely that the same thing is happening to you and you&#8217;re sick of it. With that said, let&#8217;s get started.</p>
<p>I make the assumption that you&#8217;re using Apache and have root access to your server because you&#8217;ll need to see if you have mod_rewrite enabled. If you happen to be in a hosted environment, log in to your control panel and check the documentation for managing .htaccess files. Some control panels like CPanel already have built-in modules that are designed to handle hotlink protection. If you have a dedicated server, log in through SSH or locally if you have that ability.</p>
<p>1. Check to see if the mod_rewrite module is enabled in the Apache httpd.conf file.</p>
<pre class="code">nano /etc/httpd/conf/httpd.conf</pre>
<p>Look for the &#8220;Dynamic Shared Object (DSO) Support&#8221; section and make sure you have the following line.</p>
<pre class="code">LoadModule rewrite_module modules/mod_rewrite.so</pre>
<p>If it is commented out with a # before LoadModule, delete the # and save the change. Restart Apache with</p>
<pre class="code">service httpd restart</pre>
<p>or</p>
<pre class="code">/etc/init.d/httpd restart</pre>
<p>for the change to take effect. If mod_rewrite is completely missing from your Apache config, then you may want to take a look at this article on how to <a href="http://linuxadministration.wordpress.com/2007/08/17/configure-apache/" target="_blank">configure Apache</a>.</p>
<p>2. Create a .htaccess in your web site&#8217;s html root directory or a subdirectory where you want to disable hotlinking. For this example, I only want to disable hotlinking to all image types (gif, jpeg, png, and bmp bitmaps) and have Apache return a HTTP 403 Forbidden error to the leech site. You can block any file type you want, such as pdf&#8217;s, mp3&#8217;s, etc. You could also serve up an error image to the leech saying something to the effect of &#8220;This image was hotlinked from www.yourdomain.com.&#8221;</p>
<pre class="code">touch .htaccess
nano .htaccess</pre>
<p>3. Add this code to your .htaccess file, make the appropriate changes like changing yourdomain.com to your actual domain name, and finally save the .htaccess file.</p>
<pre class="code">&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(.+\.)?yourdomain\.com [NC]
RewriteRule .*\.(jpe?g|gif|bmp|png)$ - [NC,F]
&lt;/IfModule&gt;</pre>
<p>The matching is done with regular expressions, so you&#8217;ll need to know that before you can do complex cases. In short, what this code does is first look for empty referrers, matches your domain by any or no specified subdomains (case insensitive [NC]), rewrite the URL if any jpeg, jpg, gif, bmp, or png is requested (case insensitive [NC]) with a 403 Forbidden ([F]).</p>
<p>By issuing a 403 Forbidden, no image content will be sent back to the leech server, therefore your bandwidth will not be bled dry by hotlinking. As I mentioned earlier, you can send back an error image in place of the actual requested image, however you&#8217;ll need to change the RewriteRule line to something like this.</p>
<pre class="code">RewriteRule .*\.(jpe?g|gif|bmp|png)$ /images/sorry.jpe [L]</pre>
<p>Take note at the returned image file name. We send back a jpeg variant (JPE) because we&#8217;re set on blocking the other image types. If you send back a file type that you&#8217;re blocking, you&#8217;ll likely get a 500 Internal Server Error like I did when I first set up hotlink protection. It makes sense, why send back what you&#8217;re blocking in the first place. I opted for the 403 Forbidden approach for my sites instead.</p>
<p><strong>Sources:</strong><br />
<a href="http://altlab.com/htaccess_tutorial.html" target="_blank">http://altlab.com/htaccess_tutorial.html</a><br />
<a href="http://www.dagondesign.com/articles/hotlink-protection-with-htaccess/">http://www.dagondesign.com/articles/hotlink-protection-with-htaccess/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.tonybhimani.com/2007/11/02/hotlink-protection-with-apache-mod_rewrite-and-htaccess/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Custom SquirrelMail Login Pages for Virtual Hosts mini-HOWTO</title>
		<link>http://www.tonybhimani.com/2007/10/13/custom-squirrelmail-login-pages-for-virtual-hosts-mini-howto/</link>
		<comments>http://www.tonybhimani.com/2007/10/13/custom-squirrelmail-login-pages-for-virtual-hosts-mini-howto/#comments</comments>
		<pubDate>Sat, 13 Oct 2007 21:27:49 +0000</pubDate>
		<dc:creator>Tony</dc:creator>
				<category><![CDATA[HOWTOs]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.tonybhimani.com/2007/10/13/custom-squirrelmail-login-pages-for-virtual-hosts-mini-howto/</guid>
		<description><![CDATA[Originally posted on August 8, 2006 9:57 PM
This little tutorial will show you how to create custom SquirrelMail login pages for many virtual hosts, or in plain English, you have one copy of SquirrelMail and host many web sites on a single server. The purpose is to provide a unique login page for each web [...]]]></description>
			<content:encoded><![CDATA[<p><font size="1">Originally posted on August 8, 2006 9:57 PM</font></p>
<p>This little tutorial will show you how to create custom SquirrelMail login pages for many virtual hosts, or in plain English, you have one copy of SquirrelMail and host many web sites on a single server. The purpose is to provide a unique login page for each web site domain without installing multiple copies of SquirrelMail. This is very useful if you are running a webhosting business or you host your friend&#8217;s web sites (like I do) and you don&#8217;t want SquirrelMail branded with your name but theirs. If that isn&#8217;t a good enough reason then how about the fact that the default SquirrelMail login page is boring and you should jazz it up with a custom web site theme.</p>
<p>The following screenshots are examples of some webmail login pages on my server. They all use the same copy of SquirrelMail (version 1.4.6) but with my tweaks each domain has a custom login page.</p>
<div style="width:450px;overflow:auto;white-space:nowrap;"><a href="http://www.tonybhimani.com/files/custom_sqmail/webmail_xenocafe.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/custom_sqmail/thumb_webmail_xenocafe.jpg" border="0" alt="XenoCafe WebMail Login Page" /></a> <a href="http://www.tonybhimani.com/files/custom_sqmail/webmail_pineapplenow.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/custom_sqmail/thumb_webmail_pineapplenow.jpg" border="0" alt="PineappleNOW! WebMail Login Page" /></a> <a href="http://www.tonybhimani.com/files/custom_sqmail/webmail_salina.jpg" target="_blank"><img src="http://www.tonybhimani.com/files/custom_sqmail/thumb_webmail_salina.jpg" border="0" alt="Salina's WebMail Login Page" /></a></div>
<p>This walkthrough makes the assumption that you have HTML, PHP, and some graphic design skills. To edit the SquirrelMail files you should know how to copy and paste and understand PHP, but to create your own custom templates you&#8217;ll need to know HTML, PHP, and graphics. You should also have root access to your server or have the ability to upload the modified SquirrelMail files to your server. The other obvious assumption is that you have SquirrelMail 1.4.6 installed and configured on your server (using another version of SquirrelMail may work, but I don&#8217;t know how much their code changed between revisions). If you don&#8217;t have SquirrelMail installed then you can check out my <a href="http://www.xenocafe.com/tutorials/linux/redhat/squirrelmail/installing_squirrelmail.php">SquirrelMail 1.4.6 tutorial on XenoCafe</a>. With that said, let&#8217;s get started.</p>
<p>1. You should already know where SquirrelMail is installed on your server and have it configured for each domain that accesses it. For this howto I&#8217;ll use the example directory location of <i>/www/webmail/html/</i> and the Apache virtual host file for webmail has a ServerAlias directive set for each domain (webmail.domain1.com, webmail.domain2.com, etc&#8230;). See my <a href="http://www.xenocafe.com/tutorials/linux/centos/apache_web_server/index.php">Apache Web Server tutorial</a> for more information on setting up virtual hosts.</p>
<p>2. The way I accomplished custom webmail login pages was to create a directory in /www/webmail/html/  called <i>hosts</i>. This directory is where all your templates are stored for each custom webmail login page and their associated images. Start by creating a host directory in your webmail root directory (for clarification, this is the same top level directory where the SquirrelMail &quot;src&quot; directory exists).</p>
<pre class="code">cd /www/webmail/html/
mkdir hosts</pre>
<p>3. There are three SquirrelMail PHP files that we&#8217;ll need to edit. The primary one is called <i>global.php</i> that resides in the functions directory. We&#8217;ll insert our custom function called <i>show_login_page</i> that makes custom logins possible. Let&#8217;s take a look at this login page function we&#8217;re creating.</p>
<pre class="code">function show_login_page( $errTitle=&quot;&quot;, $errString=&quot;&quot; ) {

  $httphost = strtolower( $_SERVER[&quot;HTTP_HOST&quot;] );

  switch ($httphost) {
    case &quot;webmail.domain1.com&quot;:
      require( SM_PATH . &quot;hosts/domain1/domain1.php&quot; );
      break;

    case &quot;domain2.com&quot;:
    case &quot;www.domain2.com&quot;:
    case &quot;webmail.domain2.com&quot;:
      include( SM_PATH . &quot;hosts/domain2/domain2.php&quot; );
      break;

    default:
      require( SM_PATH . &quot;hosts/default/default.php&quot; );
      break;
  }

}</pre>
<p>This function accepts two arguments ($errTitle and $errString). You&#8217;ll learn about these later when we modify one of the other SquirrelMail files. $httphost contains the server name of which web site the user is visiting. This is acquired from the global $_SERVER[&quot;HTTP_HOST&quot;] PHP variable. We use a switch/case structure to evaluate the HTTP HOST name. Depending on which host is visited the custom template for that host is shown for the login page. The host names are set up through Apache virtual hosts and DNS, in the case of the webmail subdomain. For www.domain.com and domain.com, it is assumed access to the site is coming from a /webmail directory. That can be established via symbolic links like so.</p>
<pre class="code">ln -s /www/webmail/html/ /www/domain/html/webmail</pre>
<p>So webmail can be accessed from http://webmail.domain.com or from http://www.domain.com/webmail since both paths map to the same physical space. You&#8217;ll see the PHP <i>include</i> function being used once a host is matched. The include function inserts your custom login page&#8217;s code as part of the HTML output to the web browser. The path to the PHP page is within the hosts directory we created earlier. For each host you want to serve custom logins you&#8217;ll create a subdirectory within hosts (I use the domain name without the ending .com, .net, etc). You&#8217;ll store your custom login page and image files within that domain directory. The last part of the switch/case is the default login page. This is shown when there are no HTTP HOST matches and thus displays the default SquirrelMail login page.</p>
<p>Open up the functions/global.php file in a text editor and add the show_login_page function to the end of the file right above the ending ?&gt; PHP tag. Customize the hosts for your server and save the file when you&#8217;re done.</p>
<p>4. Next we&#8217;ll edit the src/login.php page. We&#8217;re basically gonna strip out parts of the exsiting SquirrelMail code and replace it with a call to our show_login_page function. Make a backup copy of login.php and open the original in a text editor. Delete everything in the file and insert this code.</p>
<pre class="code">&lt;?php

/**
 * login.php -- simple login screen
 *
 * Copyright (c) 1999-2006 The SquirrelMail Project Team
 * Licensed under the GNU GPL. For full terms see the file COPYING.
 *
 * This a simple login screen. Some housekeeping is done to clean
 * cookies and find language.
 *
 * @version $Id: login.php,v 1.98.2.11 2006/02/03 22:27:55 jervfors Exp $
 * @package squirrelmail
 */

/**
 * Path for SquirrelMail required files.
 * @ignore
 */
define(&quot;SM_PATH&quot;,&quot;../&quot;);

/* SquirrelMail required files. */
require_once(SM_PATH . &quot;functions/strings.php&quot;);
require_once(SM_PATH . &quot;config/config.php&quot;);
require_once(SM_PATH . &quot;functions/i18n.php&quot;);
require_once(SM_PATH . &quot;functions/plugin.php&quot;);
require_once(SM_PATH . &quot;functions/constants.php&quot;);
require_once(SM_PATH . &quot;functions/page_header.php&quot;);
require_once(SM_PATH . &quot;functions/html.php&quot;);
require_once(SM_PATH . &quot;functions/global.php&quot;);
require_once(SM_PATH . &quot;functions/forms.php&quot;);

/**
 * $squirrelmail_language is set by a cookie when the user selects
 * language and logs out
 */
set_up_language($squirrelmail_language, TRUE, TRUE);

/**
 * Find out the base URI to set cookies.
 */
if (!function_exists(&quot;sqm_baseuri&quot;)){
    require_once(SM_PATH . &quot;functions/display_messages.php&quot;);
}
$base_uri = sqm_baseuri();

/*
 * In case the last session was not terminated properly, make sure
 * we get a new one.
 */

sqsession_destroy();

header(&quot;Pragma: no-cache&quot;);

do_hook(&quot;login_cookie&quot;);

$loginname_value = (sqGetGlobalVar(&quot;loginname&quot;, $loginname) ? htmlspecialchars($loginname) : &quot;&quot;);

if(sqgetGlobalVar(&quot;mailto&quot;, $mailto)) {
    $rcptaddress = &quot;&lt;input type=\&quot;hidden\&quot; name=\&quot;mailto\&quot; value=\&quot;$mailto\&quot; /&gt;\n&quot;;
} else {
    $rcptaddress = &quot;&quot;;
}

<strong>show_login_page();</strong>

?&gt;</pre>
<p>Save your changes when you&#8217;re done and then we&#8217;ll move on to the last file.</p>
<p>5. The last file we edit is functions/display_messages.php. This file contains functions to display any messages (error or otherwise) on the screen, such as login failures, IMAP failures, etc. We need to change the logout_error function so when a login failure occurs that our custom page is shown instead of the default SquirrelMail version. Replace the logout_error function with this code.</p>
<pre class="code">function logout_error( $errString, $errTitle = &quot;&quot; ) {

    list($junk, $errString, $errTitle) = do_hook(&quot;logout_error&quot;, $errString, $errTitle);

    if ( $errTitle == &quot;&quot; ) {
        $errTitle = $errString;
    }

   <strong>show_login_page($errTitle, $errString);</strong>

}</pre>
<p>If you were wondering about those arguments to our show_login_page function, now you can see what they&#8217;re for. SquirrelMail uses a hook to capture error messages on events. All we are doing is passing those error values to our login page function. When you intially go to the page, no errors are shown. If you login in and provide invalid information, our same login page will be shown again, but this time it&#8217;ll have the error messages within it. It&#8217;s similar to a postback but the URL is different. When we defined our login page function, we initialized those arguments with default null string values so no errors would show. When logout_error is called we pass the errors so they will be shown.</p>
<p>6. SquirrelMail&#8217;s PHP files are done so what&#8217;s left is to go over the steps of creating a custom login theme. I&#8217;ll now go over the parts you need to include when creating a template. Here is an example of the default template.</p>
<pre class="code">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;

&lt;html&gt;

&lt;head&gt;
&lt;meta name=&quot;robots&quot; content=&quot;noindex,nofollow&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;../themes/css/verdana-10.css&quot; /&gt;
&lt;title&gt;Domain - Login<strong>&lt;?php echo (($errTitle != &quot;&quot; ) ? &quot; - &quot;.$errTitle : &quot;&quot;); ?&gt;</strong>&lt;/title&gt;&lt;script language=&quot;JavaScript&quot; type=&quot;text/javascript&quot;&gt;
&lt;!--
  function squirrelmail_loginpage_onload() {
    document.forms&#91;0&#93;.js_autodetect_results.value = &quot;<strong>&lt;?php echo SMPREF_JS_ON; ?&gt;</strong>&quot;;
    var textElements = 0;
    for (i = 0; i &lt; document.forms&#91;0&#93;.elements.length; i++) {
      if (document.forms&#91;0&#93;.elements&#91;i&#93;.type == &quot;text&quot; || document.forms&#91;0&#93;.elements&#91;i&#93;.type == &quot;password&quot; ) {
        textElements++;
        if (textElements == <strong>&lt;?php echo (isset($loginname) ? 2 : 1); ?&gt;</strong>) {
          document.forms&#91;0&#93;.elements&#91;i&#93;.focus();
          break;
        }
      }
    }
  }
// --&gt;
&lt;/script&gt;

&lt;style type=&quot;text/css&quot;&gt;
&lt;!--
  /* avoid stupid IE6 bug with frames and scrollbars */
  body {
      voice-family: &quot;\&quot;}\&quot;&quot;;
      voice-family: inherit;
      width: expression(document.documentElement.clientWidth - 30);
  }
--&gt;
&lt;/style&gt;

&lt;/head&gt;

&lt;body text=&quot;#000000&quot; bgcolor=&quot;#ffffff&quot; link=&quot;#0000cc&quot; vlink=&quot;#0000cc&quot; alink=&quot;#0000cc&quot; onLoad=&quot;squirrelmail_loginpage_onload();&quot;&gt;
&lt;form action=&quot;redirect.php&quot; method=&quot;post&quot;&gt;
&lt;table bgcolor=&quot;#ffffff&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; width=&quot;100%&quot;&gt;&lt;tr&gt;&lt;td align=&quot;center&quot;&gt;&lt;center&gt;&lt;img src=&quot;http://webmail.domain.com/images/domain_logo.gif&quot; alt=&quot;Domain Logo&quot; width=&quot;180&quot; height=&quot;50&quot; /&gt;&lt;br /&gt;
&lt;small&gt;SquirrelMail version 1.4.6&lt;br /&gt;
  By the SquirrelMail Project Team&lt;br /&gt;&lt;/small&gt;
&lt;table bgcolor=&quot;#ffffff&quot; border=&quot;0&quot; width=&quot;350&quot;&gt;&lt;tr&gt;&lt;td bgcolor=&quot;#dcdcdc&quot; align=&quot;center&quot;&gt;&lt;b&gt;Domain Login&lt;/b&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td bgcolor=&quot;#ffffff&quot; align=&quot;left&quot;&gt;
&lt;table bgcolor=&quot;#ffffff&quot; align=&quot;center&quot; border=&quot;0&quot; width=&quot;100%&quot;&gt;&lt;tr&gt;&lt;td align=&quot;right&quot; width=&quot;30%&quot;&gt;Name:&lt;/td&gt;
&lt;td align=&quot;left&quot; width=&quot;*&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;login_username&quot; value=&quot;<strong>&lt;?php echo $loginname_value; ?&gt;</strong>&quot; /&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;&lt;td align=&quot;right&quot; width=&quot;30%&quot;&gt;Password:&lt;/td&gt;
&lt;td align=&quot;left&quot; width=&quot;*&quot;&gt;&lt;input type=&quot;password&quot; name=&quot;secretkey&quot; /&gt;
&lt;input type=&quot;hidden&quot; name=&quot;js_autodetect_results&quot; value=&quot;<strong>&lt;?php echo SMPREF_JS_OFF; ?&gt;</strong>&quot; /&gt;
<strong>&lt;?php echo $rcptaddress; ?&gt;</strong>
&lt;input type=&quot;hidden&quot; name=&quot;just_logged_in&quot; value=&quot;1&quot; /&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;center&gt;&lt;input type=&quot;submit&quot; value=&quot;Login&quot; /&gt;
&lt;/center&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;br&gt;<strong>&lt;?php if ($errString != &quot;&quot; ) { echo &quot;&lt;center&gt;&lt;font size=\&quot;2\&quot; face=\&quot;Arial, Helvetica, sans-serif\&quot; color=\&quot;#ff0000\&quot;&gt;&lt;strong&gt;$errString&lt;/strong&gt;&lt;/font&gt;&lt;/center&gt;&quot;; } ?&gt;</strong>
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/form&gt;
&lt;/body&gt;&lt;/html&gt;</pre>
<p>The code pieces in bold should be included in your template. I won&#8217;t go in depth over the code, that&#8217;s why I said you should know HTML and PHP.</p>
<p>I&#8217;ve included a zip file containing the altered PHP files and a couple templates to give you examples to follow when creating your own custom login pages. Be sure to read the README file included in the zip.</p>
<p><strong>Source Files:</strong> <a href="http://www.tonybhimani.com/files/custom_sqmail/sqmail-custom-logins.zip">sqmail-custom-logins.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.tonybhimani.com/2007/10/13/custom-squirrelmail-login-pages-for-virtual-hosts-mini-howto/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Sitemaps mini-HOWTO</title>
		<link>http://www.tonybhimani.com/2007/10/12/google-sitemaps-mini-howto/</link>
		<comments>http://www.tonybhimani.com/2007/10/12/google-sitemaps-mini-howto/#comments</comments>
		<pubDate>Sat, 13 Oct 2007 05:02:19 +0000</pubDate>
		<dc:creator>Tony</dc:creator>
				<category><![CDATA[HOWTOs]]></category>

		<guid isPermaLink="false">http://www.tonybhimani.com/2007/10/12/google-sitemaps-mini-howto/</guid>
		<description><![CDATA[Originally posted on August 3, 2006 3:08 PM
This mini howto is for information on getting started with Google Sitemaps. Using Google Sitemaps isn&#8217;t difficult, but I felt like writing a simple walkthrough for everyone just in case they might be having problems getting started. Please note these instructions assume your web site is hosted on [...]]]></description>
			<content:encoded><![CDATA[<p><font size="1">Originally posted on August 3, 2006 3:08 PM</font></p>
<p>This mini howto is for information on getting started with <a href="http://www.google.com/webmasters/sitemaps">Google Sitemaps</a>. Using Google Sitemaps isn&#8217;t difficult, but I felt like writing a simple walkthrough for everyone just in case they might be having problems getting started. Please note these instructions assume your web site is hosted on Linux and you have shell access to the server. Google offers a free service called Google Sitemaps that lets you submit all your web site URLs so their spiders know when they have changed and can produce smarter and fresher search results. Google Sitemaps actually does more than that. In fact it tells you if you have any broken links, what search terms your links are showing up under in the search engine result pages (SERPs), and which terms people are clicking on. It&#8217;s a neat little service.</p>
<p><a href="http://www.google.com/webmasters/sitemaps/">http://www.google.com/webmasters/sitemaps/</a></p>
<p>Here&#8217;s how it works in a nutshell.</p>
<p>1. Create a free account with Google or if you have a Gmail account you can use those credentials to log in.</p>
<p><a href="http://www.tonybhimani.com/files/google_sitemaps/gsm1.gif" target="_blank"><img src="http://www.tonybhimani.com/files/google_sitemaps/thumb_gsm1.gif" alt="" /></a></p>
<p>2. Once you log in, you tell Sitemaps your web site address and then it asks you to verify it&#8217;s your web site.</p>
<p><a href="http://www.tonybhimani.com/files/google_sitemaps/gsm2.gif" target="_blank"><img src="http://www.tonybhimani.com/files/google_sitemaps/thumb_gsm2.gif" alt="" /></a> <a href="http://www.tonybhimani.com/files/google_sitemaps/gsm3.gif" target="_blank"><img src="http://www.tonybhimani.com/files/google_sitemaps/thumb_gsm3.gif" alt="" /></a></p>
<p>3. To verify that the web site is indeed yours, Google gives you a couple of options to verify. One verification method is creating a html file in your webspace. The other is adding a meta tag to a web page.  I opt for the file creation so I don&#8217;t have to do any editing.</p>
<p><a href="http://www.tonybhimani.com/files/google_sitemaps/gsm4.gif" target="_blank"><img src="http://www.tonybhimani.com/files/google_sitemaps/thumb_gsm4.gif" alt="" /></a></p>
<p>Create an empty file and give it the name of the Google HTML. In this case it&#8217;s google4c293907f2980933.html. If you have SSH or Telnet access to your web site, you can also log in and use the touch command to create the file.</p>
<pre class="code">touch google4c293907f2980933.html</pre>
<p>After you upload or touch the HTML file, click the Verify button. Once verified, click on the Sitemaps tab.</p>
<p><a href="http://www.tonybhimani.com/files/google_sitemaps/gsm5.gif" target="_blank"><img src="http://www.tonybhimani.com/files/google_sitemaps/thumb_gsm5.gif" alt="" /></a></p>
<p>4. Now you need to add a sitemap for your web site. You can create your sitemap by hand or use the Google Sitemap Generator Python script. It&#8217;s easier to use the script because all you do is create a URL list and run the sitemap generator and it&#8217;ll create the XML file for you.</p>
<p>You can download the Google Sitemap Generator (<a href="http://www.sourceforge.net/project/showfiles.php?group_id=137793&amp;package_id=153422">sitemap_gen-1.4.tar.gz</a>) to your webspace, extract the contents, and then configure it.</p>
<pre class="code">tar zxvf sitemap_gen-1.4.tar.gz
cd sitemap_gen-1.4</pre>
<p>5. You need to configure sitemap generator for your web site. First you should make a copy of the example files (example_config.xml and exemple_urllist.txt) to names without the preceding &#8216;example_&#8217;.</p>
<pre class="code">cp example_config.xml config.xml
cp example_urllist.txt urllist.txt</pre>
<p>Since this is a mini howto I won&#8217;t go over every single option or advanced configurations. The purpose is to set up a simple, yet working, sitemap configuration. Open config.xml in a text editor. You&#8217;ll see a LOT of comments which you should read. To make your life easier, here is a simple configuration that will work. You can delete everything in config.xml and paste this in its place.</p>
<pre class="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;site
base_url="http://<strong>www.example.com</strong>/"
store_into="<strong>/var/www/docroot</strong>/sitemap.xml.gz"
verbose="1"
&gt;
&lt;urllist  path="urllist.txt"  encoding="UTF-8"  /&gt;
&lt;filter  action="drop"  type="wildcard"  pattern="*~" /&gt;
&lt;filter  action="drop"  type="regexp"    pattern="/\\.[^/]*" /&gt;
&lt;/site&gt;</pre>
<p>The items in bold you replace with your information. To get your webspace root directory path you can use the pwd command or ask your hosting provider. When you&#8217;re done you should save your changes.</p>
<p>Now edit your URL list. Open urllist.txt in your text editor and start adding your URLs. Here is an example.</p>
<pre class="code">...
# Example contents of the file:
#
# http://www.example.com/foo/bar
# http://www.example.com/foo/xxx.pdf lastmod=2003-12-31T14:05:06+00:00
# http://www.example.com/foo/yyy?x=12&amp;y=23 changefreq=weekly priority=0.3

# Your new URLs
http://www.example.com/
http://www.example.com/index.html
http://www.example.com/contact.html</pre>
<p>If you require more advanced usage then follow the examples in the urllist.txt file. When you&#8217;re done adding your URLs, save your changes. It&#8217;s time to generate the actual Sitemap XML file.</p>
<p>6. To build your Sitemap XML file you must have Python on your server since the Google Sitemap Generator is a Python script. Here is the command to build your XML.</p>
<pre class="code">python sitemap_gen.py --config=config.xml</pre>
<p>Here you can see it in action</p>
<pre class="code">[root@develbox sitemap_gen]# python sitemap_gen.py --config=config.xml
Reading configuration file: config.xml
Opened URLLIST file: urllist.txt
Sorting and normalizing collected URLs.
Writing Sitemap file "/web/domain/html/sitemap.xml.gz" with 3990 URLs
Notifying search engines.
Notifying: www.google.com
Count of file extensions on URLs:
2999  .html
990  .php
1  /
Number of errors: 0
Number of warnings: 0
[root@develbox sitemap_gen]#</pre>
<p>To make life easier like I did you can make a bash script with the build command and just execute that. Save it to a file named <strong>build_sitemap</strong> and <strong>chmod 755</strong> it.</p>
<pre class="code">#!/bin/bash
python sitemap_gen.py --config=config.xml</pre>
<p>7. Back in the Google Sitemaps web site, you need to specify the URL to the Sitemaps XML file so Google can check your XML file on a periodic basis.</p>
<p>On the Sitemaps tab, select Add General Web Sitemap from the dropdown control and in item 3, type in the URL of your sitemap. Google provides you an example below. Click the Add Web Sitemap button.</p>
<p><a href="http://www.tonybhimani.com/files/google_sitemaps/gsm6.gif" target="_blank"><img src="http://www.tonybhimani.com/files/google_sitemaps/thumb_gsm6.gif" alt="" /></a></p>
<p>When you build your sitemap, the XML file is gzip compressed so a .gz extension is added which makes it sitemap.xml.gz. Also, depending on the path you specified in config.xml for site:store_into, that will determine your XML file&#8217;s URL. It&#8217;s easier to keep your Sitemap XML file in top level of your webspace so its URL can be http://www.yourdomain.com/sitemap.xml.gz. Besides, it&#8217;s not like you&#8217;re storing national secrets if someone other than Google downloads your sitemap file.</p>
<p><a href="http://www.tonybhimani.com/files/google_sitemaps/gsm7.gif" target="_blank"><img src="http://www.tonybhimani.com/files/google_sitemaps/thumb_gsm7.gif" alt="" /></a></p>
<p>8. You&#8217;re done. Now you can play the waiting game. It may take a while for Google&#8217;s spiders to get to all of your pages, but they will eventually. Browse around Google Sitemaps and check out the features. It&#8217;s a nifty tool.</p>
<p>Remember, whenever you update your site you should update your URL list (urllist.txt) too, such as removing deleted pages and adding the new ones. Anytime you make a change you should rebuild the Sitemap XML file. Once it&#8217;s rebuilt, the Python script will notify Google and your fresh sitemap will be downloaded in a minute or so.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tonybhimani.com/2007/10/12/google-sitemaps-mini-howto/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
