Archive for October, 2007

Custom SquirrelMail Login Pages for Virtual Hosts mini-HOWTO

Saturday, October 13th, 2007

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 site domain without installing multiple copies of SquirrelMail. This is very useful if you are running a webhosting business or you host your friend’s web sites (like I do) and you don’t want SquirrelMail branded with your name but theirs. If that isn’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.

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.

XenoCafe WebMail Login Page PineappleNOW! WebMail Login Page Salina's WebMail Login Page

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’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’t know how much their code changed between revisions). If you don’t have SquirrelMail installed then you can check out my SquirrelMail 1.4.6 tutorial on XenoCafe. With that said, let’s get started.

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’ll use the example directory location of /www/webmail/html/ and the Apache virtual host file for webmail has a ServerAlias directive set for each domain (webmail.domain1.com, webmail.domain2.com, etc…). See my Apache Web Server tutorial for more information on setting up virtual hosts.

2. The way I accomplished custom webmail login pages was to create a directory in /www/webmail/html/ called hosts. 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 "src" directory exists).

cd /www/webmail/html/
mkdir hosts

3. There are three SquirrelMail PHP files that we’ll need to edit. The primary one is called global.php that resides in the functions directory. We’ll insert our custom function called show_login_page that makes custom logins possible. Let’s take a look at this login page function we’re creating.

function show_login_page( $errTitle="", $errString="" ) {

  $httphost = strtolower( $_SERVER["HTTP_HOST"] );

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

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

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

}

This function accepts two arguments ($errTitle and $errString). You’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["HTTP_HOST"] 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.

ln -s /www/webmail/html/ /www/domain/html/webmail

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’ll see the PHP include function being used once a host is matched. The include function inserts your custom login page’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’ll create a subdirectory within hosts (I use the domain name without the ending .com, .net, etc). You’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.

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 ?> PHP tag. Customize the hosts for your server and save the file when you’re done.

4. Next we’ll edit the src/login.php page. We’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.

<?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("SM_PATH","../");

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

/**
 * $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("sqm_baseuri")){
    require_once(SM_PATH . "functions/display_messages.php");
}
$base_uri = sqm_baseuri();

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

sqsession_destroy();

header("Pragma: no-cache");

do_hook("login_cookie");

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

if(sqgetGlobalVar("mailto", $mailto)) {
    $rcptaddress = "<input type=\"hidden\" name=\"mailto\" value=\"$mailto\" />\n";
} else {
    $rcptaddress = "";
}

show_login_page();

?>

Save your changes when you’re done and then we’ll move on to the last file.

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.

function logout_error( $errString, $errTitle = "" ) {

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

    if ( $errTitle == "" ) {
        $errTitle = $errString;
    }

   show_login_page($errTitle, $errString);

}

If you were wondering about those arguments to our show_login_page function, now you can see what they’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’ll have the error messages within it. It’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.

6. SquirrelMail’s PHP files are done so what’s left is to go over the steps of creating a custom login theme. I’ll now go over the parts you need to include when creating a template. Here is an example of the default template.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

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

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

</head>

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

<tr><td align="right" width="30%">Password:</td>
<td align="left" width="*"><input type="password" name="secretkey" />
<input type="hidden" name="js_autodetect_results" value="<?php echo SMPREF_JS_OFF; ?>" />
<?php echo $rcptaddress; ?>
<input type="hidden" name="just_logged_in" value="1" />
</td>
</tr>
</table>
</td>
</tr>
<tr><td align="left"><center><input type="submit" value="Login" />
</center></td>
</tr>
</table>
</center>
<br><?php if ($errString != "" ) { echo "<center><font size=\"2\" face=\"Arial, Helvetica, sans-serif\" color=\"#ff0000\"><strong>$errString</strong></font></center>"; } ?>
</td>
</tr>
</table>
</form>
</body></html>

The code pieces in bold should be included in your template. I won’t go in depth over the code, that’s why I said you should know HTML and PHP.

I’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.

Source Files: sqmail-custom-logins.zip

Google Sitemaps mini-HOWTO

Friday, October 12th, 2007

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’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’s a neat little service.

http://www.google.com/webmasters/sitemaps/

Here’s how it works in a nutshell.

1. Create a free account with Google or if you have a Gmail account you can use those credentials to log in.

2. Once you log in, you tell Sitemaps your web site address and then it asks you to verify it’s your web site.

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’t have to do any editing.

Create an empty file and give it the name of the Google HTML. In this case it’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.

touch google4c293907f2980933.html

After you upload or touch the HTML file, click the Verify button. Once verified, click on the Sitemaps tab.

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’s easier to use the script because all you do is create a URL list and run the sitemap generator and it’ll create the XML file for you.

You can download the Google Sitemap Generator (sitemap_gen-1.4.tar.gz) to your webspace, extract the contents, and then configure it.

tar zxvf sitemap_gen-1.4.tar.gz
cd sitemap_gen-1.4

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 ‘example_’.

cp example_config.xml config.xml
cp example_urllist.txt urllist.txt

Since this is a mini howto I won’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’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.

<?xml version="1.0" encoding="UTF-8"?>
<site
base_url="http://www.example.com/"
store_into="/var/www/docroot/sitemap.xml.gz"
verbose="1"
>
<urllist  path="urllist.txt"  encoding="UTF-8"  />
<filter  action="drop"  type="wildcard"  pattern="*~" />
<filter  action="drop"  type="regexp"    pattern="/\\.[^/]*" />
</site>

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’re done you should save your changes.

Now edit your URL list. Open urllist.txt in your text editor and start adding your URLs. Here is an example.

...
# 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&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

If you require more advanced usage then follow the examples in the urllist.txt file. When you’re done adding your URLs, save your changes. It’s time to generate the actual Sitemap XML file.

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.

python sitemap_gen.py --config=config.xml

Here you can see it in action

[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]#

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 build_sitemap and chmod 755 it.

#!/bin/bash
python sitemap_gen.py --config=config.xml

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.

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.

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’s URL. It’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’s not like you’re storing national secrets if someone other than Google downloads your sitemap file.

8. You’re done. Now you can play the waiting game. It may take a while for Google’s spiders to get to all of your pages, but they will eventually. Browse around Google Sitemaps and check out the features. It’s a nifty tool.

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’s rebuilt, the Python script will notify Google and your fresh sitemap will be downloaded in a minute or so.