Index: /trunk/phpgwapi/templates/default/login_default.php
===================================================================
--- /trunk/phpgwapi/templates/default/login_default.php	(revision 949)
+++ /trunk/phpgwapi/templates/default/login_default.php	(revision 1042)
Index: /trunk/phpgwapi/templates/azul/login_azul.php
===================================================================
--- /trunk/phpgwapi/templates/azul/login_azul.php	(revision 949)
+++ /trunk/phpgwapi/templates/azul/login_azul.php	(revision 1042)
@@ -36,5 +36,7 @@
 			case 99:
 				return '<font color="FF0000">' . lang('Blocked, too many attempts') . '</font>';
-				
+			case 200:
+				return '<font color="FF0000">' . lang('Invalid code') . '</font>';
+			break;				
 			case 10:
 				$GLOBALS['phpgw']->session->phpgw_setcookie('sessionid');
@@ -105,4 +107,21 @@
 	if(isset($passwd_type) || $_POST['submitit_x'] || $_POST['submitit_y'] || $submit)
 	{
+
+	// Primeiro testa o captcha....se houver......
+	if( $GLOBALS['phpgw_info']['server']['captcha']==1)
+		{
+		if(isset($_POST['codigo']))
+			{
+			if ($_SESSION['CAPTCHAString'] != strtoupper($_POST['codigo']))
+				{
+					$GLOBALS['phpgw']->redirect($GLOBALS['phpgw']->link('/login.php','cd=200'));
+				}
+			unset($_SESSION['CAPTCHAString']);
+			}
+		}
+	if($_POST['user'])
+		{
+			$_POST['login'] = $_POST['user'];
+		}
 ///// 	Início - Código temporário: Para renomeação de login com organização para sem. //////
 /*		$common = CreateObject('phpgwapi.common');
@@ -375,4 +394,122 @@
 	$tmpl->set_var('autocomplete', ($GLOBALS['phpgw_info']['server']['autocomplete_login'] ? 'autocomplete="off"' : ''));
 
+$aux_captcha = '';
+// soh mostra o captcha se for login sem certificado....
+if($GLOBALS['phpgw_info']['server']['captcha'] && $_GET['cd']!='300' )
+	{
+		if($valor_cookie > $GLOBALS['phpgw_info']['server']['num_badlogin'])
+			{
+				$aux_captcha = '<div class="login_label" >
+               <img src="./seguranca/captcha.php" title="'.lang('Security code').'" alt="'.lang('Security code').'" style="width:60;">
+<br />
+                <input class="input" type="text" maxlength="50" size="20" name="codigo" id="codigo" value="" >
+              </div>';
+				$tmpl->set_var('captcha',$aux_captcha);
+			}
+	}
+
+// Testa se deve incluir applet para login com certificado......
+if ($_GET['cd']=='300' && $GLOBALS['phpgw_info']['server']['certificado']==1)
+	{
+		//Zera o Cookie contador, responsavel pelo captcha
+		$valor_cookie = 1;
+		setcookie("contador", 1,0);
+
+		$link_alterna_login = '<img border=0 style="padding: 0px 5px 0px 0px" src="phpgwapi/templates/azul/images/warning.gif"/><a href="login.php" style="margin: 0px; padding: 0px; text-decoration:none;"><font color="#ffffff" face="Verdana, Arial, Helvetica, sans-serif" size="1">' . lang('Access without Digital Certificate') . '</a>';
+		$tmpl->set_var('show','none');
+		$tmpl->set_var('action','<div id="action"><img style="border:0px;margin:31px 0px 58px 0px;" src="phpgwapi/templates/azul/images/acao.gif" /></div>');
+		// gera parametro com tokens suportados ....
+		$var_tokens = '';
+		for($ii = 1; $ii < 11; $ii++)
+			{
+				if($GLOBALS['phpgw_info']['server']['test_token' . $ii . '1'])
+					$var_tokens .= $GLOBALS['phpgw_info']['server']['test_token' . $ii . '1'] . ',';
+			}
+
+		if(!$var_tokens)
+			{
+				$var_tokens = 'ePass2000Lx;/usr/lib/libepsng_p11.so,ePass2000Win;c:/windows/system32/ngp11v211.dll';
+			}
+			$param1 = "
+                                                '<param name=\"token\" value=\"" . substr($var_tokens,0,strlen($var_tokens)) . "\"> ' + 
+                                               "; 
+			$param2 = "
+                                                'token=\"" . substr($var_tokens,0,strlen($var_tokens)) . "\" ' + 
+                                               "; 
+				
+			$cod_applet =
+
+/*    // com debug ativado
+            '<script type="text/javascript">
+					if (navigator.userAgent.match(\'MSIE\')){
+						document.write(\'<object style="display:yes;width:0;height:0;vertical-align:bottom;" id="login_applet" \' +
+						\'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"> \' +
+						\'<param name="type" value="application/x-java-applet;version=1.5"> \' +
+						\'<param name="code" value="LoginApplet.class"> \' +
+						\'<param name="locale" value="' . $lang . '"> \' +
+						\'<param name="mayscript" value="true"> \' + '
+						. $param1
+						. ' \'<param name="archive" value="ExpressoCertLogin.jar,ExpressoCert.jar,commons-httpclient-3.1.jar,commons-logging-1.1.1.jar,commons-codec-1.3.jar,bcmail-jdk15-142.jar,mail.jar,activation.jar,bcprov-jdk15-142.jar"> \' +
+                        \'<param name="debug" value="true"> \' +
+						\'</object>\');
+					}
+					else {
+						document.write(\'<embed style="display:yes;width:0;height:0;vertical-align:bottom;" id="login_applet" code="LoginApplet.class" locale="' . $lang . '"\' +
+						\'archive="ExpressoCertLogin.jar,ExpressoCert.jar,commons-httpclient-3.1.jar,commons-logging-1.1.1.jar,commons-codec-1.3.jar,bcmail-jdk15-142.jar,mail.jar,activation.jar,bcprov-jdk15-142.jar" \' + '
+						. $param2
+						. ' \'type="application/x-java-applet;version=1.5" debug= "true" mayscript > \' +
+						\'<noembed> \' +
+						\'No Java Support. \' +
+						\'</noembed> \' +
+						\'</embed> \');
+					}
+				</script>';
+*/
+            // sem debug ativado
+            '<script type="text/javascript">
+					if (navigator.userAgent.match(\'MSIE\')){
+						document.write(\'<object style="display:yes;width:0;height:0;vertical-align:bottom;" id="login_applet" \' +
+						\'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"> \' +
+						\'<param name="type" value="application/x-java-applet;version=1.5"> \' + 
+						\'<param name="code" value="LoginApplet.class"> \' +
+						\'<param name="locale" value="' . $lang . '"> \' +
+						\'<param name="mayscript" value="true"> \' + ' 
+						. $param1 
+						. ' \'<param name="archive" value="ExpressoCertLogin.jar,ExpressoCert.jar,commons-httpclient-3.1.jar,commons-logging-1.1.1.jar,commons-codec-1.3.jar,bcmail-jdk15-142.jar,mail.jar,activation.jar,bcprov-jdk15-142.jar"> \' +
+						\'</object>\');
+					}
+					else {
+						document.write(\'<embed style="display:yes;width:0;height:0;vertical-align:bottom;" id="login_applet" code="LoginApplet.class" locale="' . $lang . '"\' +
+						\'archive="ExpressoCertLogin.jar,ExpressoCert.jar,commons-httpclient-3.1.jar,commons-logging-1.1.1.jar,commons-codec-1.3.jar,bcmail-jdk15-142.jar,mail.jar,activation.jar,bcprov-jdk15-142.jar" \' + '
+						. $param2  
+						. ' \'type="application/x-java-applet;version=1.5" mayscript > \' +
+						\'<noembed> \' +
+						\'No Java Support. \' +
+						\'</noembed> \' +
+						\'</embed> \');
+					}
+				</script>';
+
+
+	}
+
+else
+	{
+		if($GLOBALS['phpgw_info']['server']['certificado']==1)
+			{
+				$tmpl->set_var('show','yes');
+				$link_alterna_login = '<img border=0 style="padding: 0px" src="phpgwapi/templates/azul/images/lock1_icon.gif"/><a title="' . lang('Link to use digital certificate') . '" href="login.php?cd=300" style="margin: 0px; padding: 0px; text-decoration:none;"><font color="#ffffff" face="Verdana, Arial, Helvetica, sans-serif" size="1"><b>' . lang('Logon with my digital certificate') . '</b></font></a>';
+			}
+			$tmpl->set_var('lang_username',lang('username'));
+			$tmpl->set_var('action','');
+			$cod_applet = '';
+
+		}
+
+		$tmpl->set_var('applet',$cod_applet);
+		$tmpl->set_var('link_alterna_login',$link_alterna_login);
+		
+
 	$tmpl->pfp('loginout','login_form');
 ?>
+
Index: /trunk/phpgwapi/templates/azul/login.tpl
===================================================================
--- /trunk/phpgwapi/templates/azul/login.tpl	(revision 963)
+++ /trunk/phpgwapi/templates/azul/login.tpl	(revision 1042)
@@ -14,25 +14,25 @@
 
 	function setLogin(){
-		if( document.form_login.organization != null)
-			document.form_login.login.value = document.form_login.organization.value+'-'+document.form_login.user.value;
+		if( document.flogin.organization != null)
+			document.flogin.login.value = document.flogin.organization.value+'-'+document.flogin.user.value;
 		else
-			document.form_login.login.value = document.form_login.user.value;			
+			document.flogin.login.value = document.flogin.user.value;			
 	}
 	
 	function getLogin(){
 		var cookie = '{cookie}';
-		if( document.form_login.organization != null)
-			document.form_login.user.value= cookie.substring(cookie.indexOf('-')+1,cookie.length);
+		if( document.flogin.organization != null)
+			document.flogin.user.value= cookie.substring(cookie.indexOf('-')+1,cookie.length);
 		else	
-			document.form_login.user.value= cookie;
+			document.flogin.user.value= cookie;
 
-		if(document.form_login.user.value == '') {
-			if(document.form_login.organization != null)
-				document.form_login.organization.focus();
+		if(document.flogin.user.value == '') {
+			if(document.flogin.organization != null)
+				document.flogin.organization.focus();
 			else
-				document.form_login.user.focus();
+				document.flogin.user.focus();
 		}
 		else
-			document.form_login.passwd.focus();
+			document.flogin.passwd.focus();
 	}
 	
@@ -53,5 +53,5 @@
 		<div id="login">
       <div align="center">
-<form name="form_login" method="post" action="{login_url}" {autocomplete}>
+<form name="flogin" method="post" action="{login_url}" {autocomplete}>
 <input type="hidden" name="passwd_type" value="text">
 <input type="hidden" name="account type" value="u">
@@ -60,6 +60,7 @@
           <div id="reflexo">
            <div class="titulo_login">Expresso Livre</div>
-           <div id="mensagem" class="msgInicial" style="display:no ne;">{cd}<br>{lang_message}</div>
-            <div id="conteudo_login">
+           <div id="mensagem" class="msgInicial" >{cd}<br>{lang_message}</div>
+	   {action}
+            <div id="conteudo_login" style="display:{show};">
               <div class="login_label">
                 <label for="usuario">{lang_username}</label>
@@ -67,4 +68,5 @@
                 <input class="input" type="text" maxlength="50" size="20" name="user" id="user" value="">
               </div>
+
               <div class="login_label">
                 <label for="senha">{lang_password}</label>
@@ -72,10 +74,15 @@
                 <input class="input" type="password" maxlength="50" size="20" name="passwd" id="passwd" value="">
               </div>
-	      <br />
-              <input value="{lang_login}" name="submitit" class="button" onclick="javascript:setLogin()" type="submit" />
-            </div>
+		{captcha}
+      
+              <input value="{lang_login}" name="submitit" class="button" onclick="javascript:setLogin()" type="submit" style="margin-top:10px"/>
+            </div> 
+<div style="margin-top:5px">
+ {link_alterna_login}
+</div>
           </div>
           <div id="rodape_login">
-            <div class="ajuda"><a href="#">Ajuda</a></div>
+            <div class="ajuda"><a href="#" >Ajuda</a></div>
+
           </div>
         </div>
@@ -105,3 +112,4 @@
 </div>
 </div>
+<div>{applet}</div>
 </body></html>
Index: /trunk/login.php
===================================================================
--- /trunk/login.php	(revision 222)
+++ /trunk/login.php	(revision 1042)
@@ -1,3 +1,29 @@
 <?php
+//Valida a existencia do cookie, antes de grava-lo
+if(isset($_COOKIE['contador']))	{
+	$valor_cookie = $_COOKIE['contador'];
+	if($_POST['user'] && $_POST['passwd'])
+		{
+		$valor_cookie = $valor_cookie + 1;
+		setcookie("contador", $valor_cookie,0);
+		}
+	}
+	//Cookie inexistente: tenta gravar um
+	else
+	{
+	if (setcookie("contador", 1,0))
+		//echo "OK, cookie gravado.";
+		$valor_cookie = 1;
+		else
+		//echo "Nao gravou o cookie";
+		$valor_cookie = "9999"; // forca captcha
+	}
+// logout, inicia contador novamente.....
+if($_GET['cd']=='1' || $_COOKIE['sessionid'] || $_GET['cd'] == 10)
+	{
+	$valor_cookie = 1;
+	setcookie("contador", 1,0);
+	}
+
 	/**************************************************************************\
 	* eGroupWare login                                                         *
@@ -90,368 +116,14 @@
 	}
 
+$login_include = $GLOBALS['phpgw_info']['server']['template_dir'] . '/login_' .  $GLOBALS['phpgw_info']['login_template_set'] . '.php';
 
-	function check_logoutcode($code)
+if(!$login_include || !file_exists($login_include))
 	{
-		switch($code)
-		{
-			case 1:
-				return lang('You have been successfully logged out');
-				
-			case 2:
-				return lang('Sorry, your login has expired');
-				
-			case 4:
-				return lang('Cookies are required to login to this site.');
-				
-			case 5:
-				return '<font color="FF0000">' . lang('Bad login or password') . '</font>';
-
-			case 6:
-				return '<font color="FF0000">' . lang('Your password has expired, and you do not have access to change it') . '</font>';
-				
-			case 98:
-				return '<font color="FF0000">' . lang('Account is expired') . '</font>';
-				
-			case 99:
-				return '<font color="FF0000">' . lang('Blocked, too many attempts') . '</font>';
-				
-			case 10:
-				$GLOBALS['phpgw']->session->phpgw_setcookie('sessionid');
-				$GLOBALS['phpgw']->session->phpgw_setcookie('kp3');
-				$GLOBALS['phpgw']->session->phpgw_setcookie('domain');
-
-				//fix for bug php4 expired sessions bug
-				if($GLOBALS['phpgw_info']['server']['sessions_type'] == 'php4')
-				{
-					$GLOBALS['phpgw']->session->phpgw_setcookie(PHPGW_PHPSESSID);
-				}
-
-				return '<font color="#FF0000">' . lang('Your session could not be verified.') . '</font>';
-				
-			default:
-				return '&nbsp;';
-		}
-	}
-	
-	/* Program starts here */
-
-	if($GLOBALS['phpgw_info']['server']['auth_type'] == 'http' && isset($_SERVER['PHP_AUTH_USER']))
-	{
-		$submit = True;
-		$login  = $_SERVER['PHP_AUTH_USER'];
-		$passwd = $_SERVER['PHP_AUTH_PW'];
-		$passwd_type = 'text';
-	}
-	else
-	{
-		$passwd = $_POST['passwd'];
-		$passwd_type = $_POST['passwd_type'];
+		$aux = explode('phpgwapi',$GLOBALS['phpgw_info']['server']['template_dir']);
+		$login_include = $aux[0] . 'phpgwapi/templates/default/login_default.php';
 	}
 
-	# Apache + mod_ssl style SSL certificate authentication
-	# Certificate (chain) verification occurs inside mod_ssl
-	if($GLOBALS['phpgw_info']['server']['auth_type'] == 'sqlssl' && isset($_SERVER['SSL_CLIENT_S_DN']) && !isset($_GET['cd']))
-	{
-		# an X.509 subject looks like:
-		# /CN=john.doe/OU=Department/O=Company/C=xx/Email=john@comapy.tld/L=City/
-		# the username is deliberately lowercase, to ease LDAP integration
-		$sslattribs = explode('/',$_SERVER['SSL_CLIENT_S_DN']);
-		# skip the part in front of the first '/' (nothing)
-		while($sslattrib = next($sslattribs))
-		{
-			list($key,$val) = explode('=',$sslattrib);
-			$sslattributes[$key] = $val;
-		}
+include($login_include);
 
-		if(isset($sslattributes['Email']))
-		{
-			$submit = True;
+?>
 
-			# login will be set here if the user logged out and uses a different username with
-			# the same SSL-certificate.
-			if(!isset($_POST['login'])&&isset($sslattributes['Email']))
-			{
-				$login = $sslattributes['Email'];
-				# not checked against the database, but delivered to authentication module
-				$passwd = $_SERVER['SSL_CLIENT_S_DN'];
-			}
-		}
-		unset($key);
-		unset($val);
-		unset($sslattributes);
-	}
-
-	if(isset($passwd_type) || $_POST['submitit_x'] || $_POST['submitit_y'] || $submit)
-	{
-///// 	Início - Código temporário: Para renomeação de login com organização para sem. //////
-/*		$common = CreateObject('phpgwapi.common');
-		$ldap_conn = $common->ldapConnect();
-		$justthese = array("uid");
-		$filter="(&(phpgwAccountType=u)(uid=".$_POST['user']."))";
-		$ldap_search = ldap_search($ldap_conn, $GLOBALS['phpgw_info']['server']['ldap_context'], $filter, $justthese);
-		$ldap_info 	 = ldap_get_entries($ldap_conn, $ldap_search);
-		if ($ldap_info['count'] != 0) // Verifica se o login existe sem organização.
-		{
-			$_POST['login'] = $_POST['user'];
-		}
-		ldap_close($ldap_conn);*/
-/// 	Fim - Código temporário: Para renomeação de login com organização para sem. //////
-		if(getenv('REQUEST_METHOD') != 'POST' && $_SERVER['REQUEST_METHOD'] != 'POST' &&
-			!isset($_SERVER['PHP_AUTH_USER']) && !isset($_SERVER['SSL_CLIENT_S_DN']))
-		{
-			$GLOBALS['phpgw']->redirect($GLOBALS['phpgw']->link('/login.php','cd=5'));
-		}
-		
-		// don't get login data again when $submit is true
-		if($submit == false)
-		{
-			$login = $_POST['login'];
-		}
-		
-		if(strstr($login,'@') === False && isset($_POST['logindomain']))
-		{
-			$login .= '@' . $_POST['logindomain'];
-		}
-		elseif(!isset($GLOBALS['phpgw_domain'][$GLOBALS['phpgw_info']['user']['domain']]))
-		{
-			$login .= '@'.$GLOBALS['phpgw_info']['server']['default_domain'];
-		}
-		$GLOBALS['sessionid'] = $GLOBALS['phpgw']->session->create(strtolower($login),$passwd,$passwd_type,'u');
-
-		if(!isset($GLOBALS['sessionid']) || ! $GLOBALS['sessionid'])
-		{
-			$GLOBALS['phpgw']->redirect($GLOBALS['phpgw_info']['server']['webserver_url'] . '/login.php?cd=' . $GLOBALS['phpgw']->session->cd_reason);
-		}
-		else
-		{
-			if ($_POST['lang'] && preg_match('/^[a-z]{2}(-[a-z]{2}){0,1}$/',$_POST['lang']) &&
-			    $_POST['lang'] != $GLOBALS['phpgw_info']['user']['preferences']['common']['lang'])
-			{
-				$GLOBALS['phpgw']->preferences->add('common','lang',$_POST['lang'],'session');
-			}
-
-			if(!$GLOBALS['phpgw_info']['server']['disable_autoload_langfiles'])
-			{
-				$GLOBALS['phpgw']->translation->autoload_changed_langfiles();
-			}
-			$forward = isset($_GET['phpgw_forward']) ? urldecode($_GET['phpgw_forward']) : @$_POST['phpgw_forward'];
-			if (!$forward)
-			{
-				$extra_vars['cd'] = 'yes';
-				$forward = '/home.php';
-			}
-			else
-			{
-				list($forward,$extra_vars) = explode('?',$forward,2);
-			}
-			if ($GLOBALS['phpgw_info']['server']['use_https'] != 2)
-			{
-				$forward = 'http://'.$_SERVER['HTTP_HOST'].($GLOBALS['phpgw']->link($forward.'?cd=yes'));
-				echo "<script language='Javascript1.3'>location.href='".$forward."'</script>";
-			}
-			else
-			{
-				$GLOBALS['phpgw']->redirect_link($forward,$extra_vars);
-			}
-		}
-	}
-	else
-	{
-		// !!! DONT CHANGE THESE LINES !!!
-		// If there is something wrong with this code TELL ME!
-		// Commenting out the code will not fix it. (jengo)
-		if(isset($_COOKIE['last_loginid']))
-		{
-			$accounts = CreateObject('phpgwapi.accounts');
-			$prefs = CreateObject('phpgwapi.preferences', $accounts->name2id($_COOKIE['last_loginid']));
-
-			if($prefs->account_id)
-			{
-				$GLOBALS['phpgw_info']['user']['preferences'] = $prefs->read_repository();
-			}
-		}
-		if ($_GET['lang'])
-		{
-			$GLOBALS['phpgw_info']['user']['preferences']['common']['lang'] = $_GET['lang'];
-		}
-		elseif(!isset($_COOKIE['last_loginid']) || !$prefs->account_id)
-		{
-			// If the lastloginid cookies isn't set, we will default to the first language,
-			// the users browser accepts.
-			list($lang) = explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']);
-			/*
-			if(strlen($lang) > 2)
-			{
-				$lang = substr($lang,0,2);
-			}
-			*/
-			$GLOBALS['phpgw_info']['user']['preferences']['common']['lang'] = $lang;
-		}
-		#print 'LANG:' . $GLOBALS['phpgw_info']['user']['preferences']['common']['lang'] . '<br>';
-
-		$GLOBALS['phpgw']->translation->init();	// this will set the language according to the (new) set prefs
-		$GLOBALS['phpgw']->translation->add_app('login');
-		$GLOBALS['phpgw']->translation->add_app('loginscreen');
-		if(lang('loginscreen_message') == 'loginscreen_message*')
-		{
-			$GLOBALS['phpgw']->translation->add_app('loginscreen','en');	// trying the en one
-		}
-		if(lang('loginscreen_message') != 'loginscreen_message*')
-		{
-			$tmpl->set_var('lang_message',stripslashes(lang('loginscreen_message')));
-		}
-	}
-
-	if($GLOBALS['phpgw_info']['server']['use_prefix_organization'])
-	{
-		$organization_select = "<tr><td width=\"66\" class=\"loginLabel\">";
-		$organization_select .= lang("organization").":</td>";
-		$organization_select .="<td width=\"135\">";											
-		$organization_select .="<select name=\"organization\">\n";		
-		
-		$obj_organization = CreateObject('phpgwapi.sector_search_ldap');
-		$organizations = $obj_organization->organization_search($GLOBALS['phpgw_info']['server']['ldap_context']);
-		
-		for ($i=0; $i<count($organizations); $i++)
-		{
-			$tmp_array[strtolower($organizations[$i])] = $organizations[$i];	
-		}
-		
-		$arrayOrganization = $tmp_array;		
-		ksort($arrayOrganization);
-		
-		foreach($arrayOrganization
-			 as $organization_name => $organization_vars)
-		{
-			$organization_select .= '<option value="' . $organization_name . '"';
-
-			if($organization_name == $_COOKIE['last_organization'])
-			{
-				$organization_select .= ' selected';
-			}
-			$organization_select .= '>' . $organization_vars . "</option>\n";
-		}
-		$organization_select .= "</select>\n";
-		$organization_select .="</td><td>&nbsp;</td></tr>";
-		$tmpl->set_var('select_organization',$organization_select);
-	}
-		
-	$domain_select = '&nbsp;';
-	$last_loginid = $_COOKIE['last_loginid'];
-	if($GLOBALS['phpgw_info']['server']['show_domain_selectbox'])
-	{
-		$domain_select = "<select name=\"logindomain\">\n";
-		foreach($GLOBALS['phpgw_domain'] as $domain_name => $domain_vars)
-		{
-			$domain_select .= '<option value="' . $domain_name . '"';
-
-			if($domain_name == $_COOKIE['last_domain'])
-			{
-				$domain_select .= ' selected';
-			}
-			$domain_select .= '>' . $domain_name . "</option>\n";
-		}
-		$domain_select .= "</select>\n";
-	}
-	elseif($last_loginid !== '')
-	{
-		reset($GLOBALS['phpgw_domain']);
-		list($default_domain) = each($GLOBALS['phpgw_domain']);
-
-		if($_COOKIE['last_domain'] != $default_domain && !empty($_COOKIE['last_domain']))
-		{
-			$last_loginid .= '@' . $_COOKIE['last_domain'];
-		}
-	}
-	$tmpl->set_var('select_domain',$domain_select);
-
-	foreach($_GET as $name => $value)
-	{
-		if(ereg('phpgw_',$name))
-		{
-			$extra_vars .= '&' . $name . '=' . urlencode($value);
-		}
-	}
-
-	if($extra_vars)
-	{
-		$extra_vars = '?' . substr($extra_vars,1);
-	}
-
-	/********************************************************\
-	* Check is the registration app is installed, activated  *
-	* And if the register link must be placed                *
-	\********************************************************/
-	
-	$cnf_reg = createobject('phpgwapi.config','registration');
-	$cnf_reg->read_repository();
-	$config_reg = $cnf_reg->config_data;
-
-	if($config_reg[enable_registration]=='True' && $config_reg[register_link]=='True')
-	{
-		$reg_link='&nbsp;<a href="registration/">'.lang('Not a user yet? Register now').'</a><br/>';
-	}
-
-	$GLOBALS['phpgw_info']['server']['template_set'] = $GLOBALS['phpgw_info']['login_template_set'];
-
-	$tmpl->set_var('register_link',$reg_link);
-	$tmpl->set_var('charset',$GLOBALS['phpgw']->translation->charset());
-	$tmpl->set_var('login_url', $GLOBALS['phpgw_info']['server']['webserver_url'] . '/login.php' . $extra_vars);
-	$tmpl->set_var('registration_url',$GLOBALS['phpgw_info']['server']['webserver_url'] . '/registration/');
-	$tmpl->set_var('version',$GLOBALS['phpgw_info']['server']['versions']['phpgwapi']);
-	$tmpl->set_var('cd',check_logoutcode($_GET['cd']));
-	$tmpl->set_var('cookie',$last_loginid);
-
-	$tmpl->set_var('lang_username',lang('username'));
-	$tmpl->set_var('lang_password',lang('password'));
-	$tmpl->set_var('lang_login',lang('login'));
-
-	$tmpl->set_var('website_title', $GLOBALS['phpgw_info']['server']['site_title']);
-	$tmpl->set_var('template_set',$GLOBALS['phpgw_info']['login_template_set']);
-	$tmpl->set_var('bg_color',($GLOBALS['phpgw_info']['server']['login_bg_color']?$GLOBALS['phpgw_info']['server']['login_bg_color']:'FFFFFF'));
-	$tmpl->set_var('bg_color_title',($GLOBALS['phpgw_info']['server']['login_bg_color_title']?$GLOBALS['phpgw_info']['server']['login_bg_color_title']:'486591'));
-
-	if($GLOBALS['phpgw_info']['server']['use_frontend_name'])
-		$tmpl->set_var('frontend_name', " - ".$GLOBALS['phpgw_info']['server']['use_frontend_name']);
-
-	if (substr($GLOBALS['phpgw_info']['server']['login_logo_file'],0,4) == 'http')
-	{
-		$var['logo_file'] = $GLOBALS['phpgw_info']['server']['login_logo_file'];
-	}
-	else
-	{
-		$var['logo_file'] = $GLOBALS['phpgw']->common->image('phpgwapi',$GLOBALS['phpgw_info']['server']['login_logo_file']?$GLOBALS['phpgw_info']['server']['login_logo_file']:'logo');
-	}
-	$var['logo_url'] = $GLOBALS['phpgw_info']['server']['login_logo_url']?$GLOBALS['phpgw_info']['server']['login_logo_url']:'http://www.eGroupWare.org';
-	if (substr($var['logo_url'],0,4) != 'http')
-	{
-		$var['logo_url'] = 'http://'.$var['logo_url'];
-	}
-	$var['logo_title'] = $GLOBALS['phpgw_info']['server']['login_logo_title']?$GLOBALS['phpgw_info']['server']['login_logo_title']:'www.eGroupWare.org';
-	$tmpl->set_var($var);
-
-	if (@$GLOBALS['phpgw_info']['server']['login_show_language_selection'])
-	{
-		$select_lang = '<select name="lang" onchange="'."location.href=location.href+(location.search?'&':'?')+'lang='+this.value".'">';
-		$langs = $GLOBALS['phpgw']->translation->get_installed_langs();
-		uasort($langs,'strcasecmp');
-		foreach ($langs as $key => $name)	// if we have a translation use it
-		{
-			$select_lang .= "\n\t".'<option value="'.$key.'"'.($key == $GLOBALS['phpgw_info']['user']['preferences']['common']['lang'] ? ' selected="1"' : '').'>'.$name.'</option>';
-		}
-		$select_lang .= "\n</select>\n";
-		$tmpl->set_var(array(
-			'lang_language' => lang('Language'),
-			'select_language' => $select_lang,
-		));
-	}
-	else
-	{
-		$tmpl->set_block('login_form','language_select');
-		$tmpl->set_var('language_select','');
-	}
-
-	$tmpl->set_var('autocomplete', ($GLOBALS['phpgw_info']['server']['autocomplete_login'] ? 'autocomplete="off"' : ''));
-
-	$tmpl->pfp('loginout','login_form');
-?>
Index: /trunk/doc-expressolivre/debian/arqs-conf/header.inc.php
===================================================================
--- /trunk/doc-expressolivre/debian/arqs-conf/header.inc.php	(revision 254)
+++ /trunk/doc-expressolivre/debian/arqs-conf/header.inc.php	(revision 1042)
@@ -10,5 +10,5 @@
 	*  option) any later version.                                              *
 	\**************************************************************************/
-	/* $Id$ */
+	/* $Id: header.inc.php.template,v 1.55.2.1 2004/08/03 14:05:35 reinerj Exp $ */
 
 	/**************************************************************************\
@@ -22,15 +22,46 @@
 	define('PHPGW_INCLUDE_ROOT','/var/www/expresso');
 	$GLOBALS['phpgw_info']['server']['header_admin_user'] = 'expresso-admin';
-	$GLOBALS['phpgw_info']['server']['header_admin_password'] = 'HEADER_PWD';
+	$GLOBALS['phpgw_info']['server']['header_admin_password'] = 'e8d95a51f3af4a3b134bf6bb680a213a';
 	$GLOBALS['phpgw_info']['server']['setup_acl'] = '';
 
+	// Opcoes exlusivas para o Carteiro Expresso 
+	$GLOBALS['phpgw_info']['server']['captcha'] = 1;       /* troque para 1 para usar o captcha     */
+	$GLOBALS['phpgw_info']['server']['num_badlogin'] = 2;       /*Numero de falhas no login antes de pedir o captcha */
+	$GLOBALS['phpgw_info']['server']['atributoexpiracao'] = 'phpgwLastPasswdChange';
+	$GLOBALS['phpgw_info']['server']['atributousuarios'] = 'person';
+	$GLOBALS['phpgw_info']['server']['politicasenhas'] = 'expresso';  /* expresso ou diretorio */
+	$GLOBALS['phpgw_info']['server']['diretorioescravo'] = 'nao'; /* 1 ou 0  */
+	$GLOBALS['phpgw_info']['server']['certificado'] = 1;    /* troque para 1 para usar o Certificado */
+        $GLOBALS['phpgw_info']['server']['use_assinar_criptografar'] = 1;	
+	$GLOBALS['phpgw_info']['server']['num_max_certs_to_cipher'] = 10;
+	#$GLOBALS['phpgw_info']['server']['corporative_certificate'] = '{CORPORATIVE_CERTIFICATE}';	
+	$GLOBALS['phpgw_info']['server']['versao-Serpro'] = '1.0';           /* soh para o SERPRO */
+	
 	// Opcoes exlusivas para o Expresso Livre
-	$GLOBALS['phpgw_info']['server']['use_https'] = 0;
-	$GLOBALS['phpgw_info']['server']['sugestoes_email_to'] = '';
+	$GLOBALS['phpgw_info']['server']['use_https'] = 2;
+	$GLOBALS['phpgw_info']['server']['sugestoes_email_to'] = '';      /* email para receber sugestoes  */
 	$GLOBALS['phpgw_info']['server']['domain_name'] = '';
-	
+	$GLOBALS['phpgw_info']['server']['use_prefix_organization'] = False;
+	$GLOBALS['phpgw_info']['server']['use_mailman'] = 0;
+	$GLOBALS['phpgw_info']['server']['contexto_geral'] = '{CONTEXTO_GERAL}';
+
+
+	/********** INICIO BLOCO MAILMAN ************/
+
+	// Opcoes usadas com servidor de listas Mailman
+	$GLOBALS['phpgw_info']['server']['use_mailman'] = '0';
+	$GLOBALS['phpgw_info']['server']['dn_listas'] = '';
+	$GLOBALS['phpgw_info']['server']['dn_listadmin'] = '';
+	$GLOBALS['phpgw_info']['server']['dominio_listas'] = '';
+	$GLOBALS['phpgw_info']['server']['porta_mailman'] = '';
+	$GLOBALS['phpgw_info']['server']['host_mailman'] = '';
+	$GLOBALS['phpgw_info']['server']['url_mailman'] = '';
+
+	/********** FIM BLOCO MAILMAN ***************/
+
+
 	/* eGroupWare domain-specific db settings */
 	$GLOBALS['phpgw_domain']['default'] = array(
-		'db_host' => '127.0.0.1',
+		'db_host' => 'localhost',
 		'db_port' => '5432',
 		'db_name' => 'expresso',
@@ -41,5 +72,5 @@
 		// This will limit who is allowed to make configuration modifications
 		'config_user'   => 'expresso-admin',
-		'config_passwd' => 'HEADER_PWD'
+		'config_passwd' => 'e8d95a51f3af4a3b134bf6bb680a213a'
 	);
 
Index: /trunk/admin/inc/hook_admin.inc.php
===================================================================
--- /trunk/admin/inc/hook_admin.inc.php	(revision 1035)
+++ /trunk/admin/inc/hook_admin.inc.php	(revision 1042)
@@ -83,11 +83,5 @@
 			$file['CASCRLS']    = $GLOBALS['phpgw']->link('../seguranca/security_admin.php');
 		}
-	}
-
-
-	if (! $GLOBALS['phpgw']->acl->check('asyncservice_access',1,'admin'))
-	{
-		$file['subversion']    = $GLOBALS['phpgw']->link('subversion.php');
-	}
+	} 
 
 	if (! $GLOBALS['phpgw']->acl->check('site_config_access',1,'admin'))
Index: /trunk/admin/templates/azul/config.tpl
===================================================================
--- /trunk/admin/templates/azul/config.tpl	(revision 1029)
+++ /trunk/admin/templates/azul/config.tpl	(revision 1042)
@@ -52,4 +52,31 @@
    <tr class="th">
     <td colspan="2">&nbsp;<b>{lang_security}</b></td>
+   </tr>
+
+   <tr class="row_off">
+    <td valign="top"><pre>
+Nome, um ponto-e-virgula como separador, e o caminho completo para os drivers dos tokens 
+que ser&atilde;o suportados (At&eacute; 10):<br/>
+
+   Ex:  ePass2000Lx;/usr/lib/libepsng_p11.so
+	ePass2000Win;c:/windows/system32/ngp11v211.dll 
+       
+        Estes s&atilde;o os drivers para o token ePass2000, utilizado no Serpro,
+        nos ambientes Linux e Windows respectivamente.
+
+        <b>Aten&ccedil;&atilde;o</b>: O caminho no ambiente Windows n&atilde;o deve usar contra barra. 
+         </pre>	</td>
+    <td>
+	<input name="newsettings[test_token11]" value="{value_test_token11}"><br/>
+	<input name="newsettings[test_token21]" value="{value_test_token21}"><br/>
+	<input name="newsettings[test_token31]" value="{value_test_token31}"><br/>
+	<input name="newsettings[test_token41]" value="{value_test_token41}"><br/>
+	<input name="newsettings[test_token51]" value="{value_test_token51}"><br/>
+	<input name="newsettings[test_token61]" value="{value_test_token61}"><br/>
+	<input name="newsettings[test_token71]" value="{value_test_token71}"><br/>
+	<input name="newsettings[test_token81]" value="{value_test_token81}"><br/>
+	<input name="newsettings[test_token91]" value="{value_test_token91}"><br/>
+	<input name="newsettings[test_token101]" value="{value_test_token101}"><br/>
+    </td>
    </tr>
 
Index: /trunk/contactcenter/setup/external_catalogs.inc.php
===================================================================
--- /trunk/contactcenter/setup/external_catalogs.inc.php	(revision 404)
+++ /trunk/contactcenter/setup/external_catalogs.inc.php	(revision 1042)
@@ -3,5 +3,5 @@
  * Created on 20/08/2007 Por Bruno costa
  *
- *	Arquivo de configuracao de catalogos externos
+ *	Arquivo de configuraï¿œï¿œo de catï¿œlogos externos
  *
  */
@@ -23,8 +23,7 @@
  * 						'obj'		=>	'objectClass that will be used in searches',
  * 						'branch'	=>	strtolower('attribute used as branches in the catalog tree'),
- * 						'quicksearch'   =>      'ExpressoMail's search',
- *                      'max_results'   =>      'Ldap's search limit',
+ 						'quicksearch	=>	'ExpressoMail's search',
+						'max_results'	=>	'Ldap's search limit',
  * 					),
- * 
  * 					2 	=>	array(
  * 						...
@@ -47,3 +46,166 @@
  *
  */
+ 
+ $external_srcs = array(
+/*				1 => array(
+					'name'		=> 'Exchange Fazenda',
+					'host'		=> '10.30.2.21',
+					'dn'		=> 'dc=mf,dc=correio',
+					'acc'		=> 'cn=Carteiro,ou=Serpro,dc=mf,dc=correio',
+					'pw'		=> 'bfr2000s$',
+					'obj'		=> 'person',
+					'branch'	=> '',
+                                        'quicksearch'   => true,
+                                        'max_results'   => 50,
+
+				),*/
+				1 => array(
+					'name'		=> 'Grupos Notes',
+					'host'		=> '10.30.2.25',
+					'dn'		=> 'ou=gruposNotes,dc=correiolivre,dc=serpro,dc=gov,dc=br',
+					'acc'		=> 'cn=admin,dc=correiolivre,dc=serpro,dc=gov,dc=br',
+					'pw'		=> 'correio',
+					'obj'		=> 'inetOrgPerson',
+					'branch'	=> '',
+                                        'quicksearch'   => false,
+                                        'max_result'    => 0,
+				)
+			);
+$external_mappings = array(
+/*				1 => array(
+					'contact.id_contact'               => array('dn'),
+					'contact.photo'                    => array('jpegPhoto'),
+					'contact.prefixes.prefix'          => false,
+					'contact.alias'                    => array('alias'),
+					'contact.given_names'              => array('givenName'),
+					'contact.family_names'             => array('sn'),
+					'contact.names_ordered'            => array('cn'),//,'displayName'),
+					'contact.suffixes.suffix'          => false,
+					'contact.birthdate'                => false,
+					'contact.sex'                      => false,
+					'contact.pgp_key'                  => false,
+					'contact.notes'                    => false,
+					'contact.mail_forwarding_address'  => array('mailForwardingAddress'),
+					'contact.account_type'             => false,
+                    			'contact.account_status'           => false,
+                   			'contact.account_visible'          => false,
+                    			'contact.object_class'             => array('objectClass'),
+					'contact.business_info.title'      => array('title'),
+					'contact.business_info.department' => array('ou'), // Setor do empregado...
+					'contact.business_info.empNumber'  => array('employeeNumber'), // Matricula do empregado
+					'contact.business_info.celPhone'   => array('mobile'), // Celular empresarial do empregado
+					'contact.company.company_name'     => array('o'),
+					'contact.company.company_notes'    => array('businessCategory'),
+
+					'contact.contact_related.names_ordered' => 'contact.contact_related.typeof_relation.contact_relation_name',
+					'contact.contact_related.typeof_relation.contact_relation_name' =>  array(
+						'manager'   => array('manager'),
+						'secretary' => array('secretary')
+					),
+
+					'contact.address.address1'         => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => array('street', 'st', 'postalAddress', 'homePostalAddress'),
+					),
+
+					'contact.address.postal_code'      => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => array('PostalCode'),
+					),
+
+					'contact.address.city.city_name'   => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => array('l'),
+					),
+
+					'contact.address.city.state.state_name'       => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => false,
+					),
+
+					'contact.address.city.country.id_country'     => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => array('c')
+					),
+
+					'contact.connection.connection_value'         => 'contact.connection.typeof_connection.contact_connection_type_name',
+					'contact.connection.typeof_connection.contact_connection_type_name' => array (
+						'email'  => array('mail'),
+						'phone'  => array('telephoneNumber'),
+					//	'mobile' => array('mobile'),
+						'pager'  => array('pager'),
+						'fax'    => array('facsimileTelephoneNumber'),
+						'telex'  => array('telexNumber')
+					),
+                                ),*/
+				1 => array(
+					'contact.id_contact'               => array('dn'),
+					'contact.photo'                    => array('jpegPhoto'),
+					'contact.prefixes.prefix'          => false,
+					'contact.alias'                    => array('alias'),
+					'contact.given_names'              => array('givenName'),
+					'contact.family_names'             => array('sn'),
+					'contact.names_ordered'            => array('cn'),//,'displayName'),
+					'contact.suffixes.suffix'          => false,
+					'contact.birthdate'                => false,
+					'contact.sex'                      => false,
+					'contact.pgp_key'                  => false,
+					'contact.notes'                    => false,
+					'contact.mail_forwarding_address'  => array('mailForwardingAddress'),
+					'contact.account_type'             => false,
+                    			'contact.account_status'           => false,
+                   			'contact.account_visible'          => false,
+                    			'contact.object_class'             => array('objectClass'),
+					'contact.business_info.title'      => array('title'),
+					'contact.business_info.department' => array('ou'), // Setor do empregado...
+					'contact.business_info.empNumber'  => array('employeeNumber'), // Matricula do empregado
+					'contact.business_info.celPhone'   => array('mobile'), // Celular empresarial do empregado
+					'contact.company.company_name'     => array('o'),
+					'contact.company.company_notes'    => array('businessCategory'),
+
+					'contact.contact_related.names_ordered' => 'contact.contact_related.typeof_relation.contact_relation_name',
+					'contact.contact_related.typeof_relation.contact_relation_name' =>  array(
+						'manager'   => array('manager'),
+						'secretary' => array('secretary')
+					),
+
+					'contact.address.address1'         => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => array('street', 'st', 'postalAddress', 'homePostalAddress'),
+					),
+
+					'contact.address.postal_code'      => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => array('PostalCode'),
+					),
+
+					'contact.address.city.city_name'   => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => array('l'),
+					),
+
+					'contact.address.city.state.state_name'       => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => false,
+					),
+
+					'contact.address.city.country.id_country'     => 'contact.address.typeof_address.contact_address_type_name',
+					'contact.address.typeof_address.contact_address_type_name' => array(
+						'home' => array('c')
+					),
+
+					'contact.connection.connection_value'         => 'contact.connection.typeof_connection.contact_connection_type_name',
+					'contact.connection.typeof_connection.contact_connection_type_name' => array (
+						'email'  => array('mail'),
+						'phone'  => array('telephoneNumber'),
+					//	'mobile' => array('mobile'),
+						'pager'  => array('pager'),
+					//	'fax'    => array('facsimileTelephoneNumber'),
+						'telex'  => array('telexNumber')
+					),
+					
+                                    
+				),
+		);
+
 ?>
Index: /trunk/setup/manageheader.php
===================================================================
--- /trunk/setup/manageheader.php	(revision 1035)
+++ /trunk/setup/manageheader.php	(revision 1042)
@@ -10,4 +10,5 @@
   \**************************************************************************/
 
+  /* $Id: manageheader.php,v 1.1 2006/09/15 14:36:29 niltonneto Exp $ */
 
 	$phpgw_info = array();
@@ -174,4 +175,5 @@
 	$action = @get_var('action',Array('POST'));
 	list($action) = @each($action);
+
 	switch($action)
 	{
@@ -232,4 +234,5 @@
 				echo lang('Please check read/write permissions on directories, or back up and use another option.') . '<br>';
 				echo '</td></tr></table></body></html>';
+				break;
 			}
 			break;
@@ -591,14 +594,54 @@
 				case '0':
 					$setup_tpl->set_var('use_https_0',' checked');
+					$setup_tpl->set_var('div_cert',' style="display:none" ');
 					break;
 				case '1':
 					$setup_tpl->set_var('use_https_1',' checked');
+					$setup_tpl->set_var('div_cert',' ');
 					break;
 				case '2':
 					$setup_tpl->set_var('use_https_2',' checked');
-					break;
-			}
-
-            switch($GLOBALS['phpgw_info']['server']['use_assinar_criptografar'])
+					$setup_tpl->set_var('div_cert',' ');
+					break;
+			}
+			
+			switch($GLOBALS['phpgw_info']['server']['certificado'])
+			{
+				case '0':
+					$setup_tpl->set_var('certificado_0',' checked');
+					break;
+				case '1':
+					$setup_tpl->set_var('certificado_1',' checked');
+					break;
+				default:
+					$setup_tpl->set_var('certificado_0',' checked');
+			}
+			
+			switch($GLOBALS['phpgw_info']['server']['captcha'])
+			{
+				case '0':
+					$setup_tpl->set_var('captcha_0',' checked');
+					$setup_tpl->set_var('div_badlogin',' style="display:none" ');
+					break;
+				case '1':
+					$setup_tpl->set_var('captcha_1',' checked');
+					break;
+				default:
+					$setup_tpl->set_var('captcha_0',' checked');
+					$setup_tpl->set_var('div_badlogin',' style="display:none" ');
+			}
+
+
+			if($GLOBALS['phpgw_info']['server']['num_badlogin'])
+			{
+				$setup_tpl->set_var('num_badlogin',$GLOBALS['phpgw_info']['server']['num_badlogin']);
+			}
+			else
+			{
+				$setup_tpl->set_var('num_badlogin','0');
+			}
+			
+			
+			switch($GLOBALS['phpgw_info']['server']['use_assinar_criptografar'])
 			{
 				case '0':
@@ -611,5 +654,5 @@
 					$setup_tpl->set_var('use_assinar_criptografar_0',' checked');
 			}
-
+			
 			if($GLOBALS['phpgw_info']['server']['num_max_certs_to_cipher'])
 			{
@@ -620,4 +663,101 @@
 				$setup_tpl->set_var('num_max_certs_to_cipher','10');
 			}
+			/*
+			if($GLOBALS['phpgw_info']['server']['corporative_certificate'])
+			{
+				$setup_tpl->set_var('corporative_certificate',$GLOBALS['phpgw_info']['server']['corporative_certificate']);
+			}
+			else
+			{
+				$setup_tpl->set_var('corporative_certificate','');
+			}
+			*/
+			if($GLOBALS['phpgw_info']['server']['atributoexpiracao'])
+			{
+				$setup_tpl->set_var('atributoexpiracao',$GLOBALS['phpgw_info']['server']['atributoexpiracao']);
+			}	
+			else
+			{
+				$setup_tpl->set_var('atributoexpiracao', 'phpgwaccountexpires');
+			}	
+			if($GLOBALS['phpgw_info']['server']['atributousuarios'])
+			{
+				$setup_tpl->set_var('atributousuarios',$GLOBALS['phpgw_info']['server']['atributousuarios']);
+			}	
+			else
+			{
+				$setup_tpl->set_var('atributousuarios', 'serprousr');
+			}	
+			switch($GLOBALS['phpgw_info']['server']['politicasenhas'])
+			{
+				case 'expresso':
+					$setup_tpl->set_var('politicasenhas_expresso',' checked');
+					break;
+				case 'diretorio':
+					$setup_tpl->set_var('politicasenhas_diretorio',' checked');
+					break;
+				default:
+					$setup_tpl->set_var('politicasenhas_expresso',' checked');
+			}	
+			switch($GLOBALS['phpgw_info']['server']['diretorioescravo'])
+			{
+				case 'sim':
+					$setup_tpl->set_var('diretorioescravo_true',' checked');
+					break;
+				case 'nao':
+					$setup_tpl->set_var('diretorioescravo_false',' checked');
+					break;
+				default:
+					$setup_tpl->set_var('diretorioescravo_false',' checked');
+			}
+
+/********************* INICIO BLOCO MAILMAN **************************/
+			
+			switch($GLOBALS['phpgw_info']['server']['use_mailman'])
+			{
+				case '0':
+					$setup_tpl->set_var('use_mailman_0',' checked');
+					$setup_tpl->set_var('div_mailman',' style="display: none;" ');
+					break;
+				case '1':
+					$setup_tpl->set_var('use_mailman_1',' checked');
+					$setup_tpl->set_var('div_mailman','');
+					break;
+				default:
+					$setup_tpl->set_var('use_mailman_0',' checked');
+					$setup_tpl->set_var('div_mailman',' style="display: none;" ');
+			}	
+			
+			if($GLOBALS['phpgw_info']['server']['dn_listas'])
+			{
+				$setup_tpl->set_var('dn_listas',$GLOBALS['phpgw_info']['server']['dn_listas']);
+			}
+
+			if($GLOBALS['phpgw_info']['server']['dn_listadmin'])
+			{
+				$setup_tpl->set_var('dn_listadmin',$GLOBALS['phpgw_info']['server']['dn_listadmin']);
+			}
+
+			if($GLOBALS['phpgw_info']['server']['dominio_listas'])
+			{
+				$setup_tpl->set_var('dominio_listas',$GLOBALS['phpgw_info']['server']['dominio_listas']);
+			}
+
+			if($GLOBALS['phpgw_info']['server']['porta_mailman'])
+			{
+				$setup_tpl->set_var('porta_mailman',$GLOBALS['phpgw_info']['server']['porta_mailman']);
+			}
+
+			if($GLOBALS['phpgw_info']['server']['host_mailman'])
+			{
+				$setup_tpl->set_var('host_mailman',$GLOBALS['phpgw_info']['server']['host_mailman']);
+			}
+
+			if($GLOBALS['phpgw_info']['server']['url_mailman'])
+			{
+				$setup_tpl->set_var('url_mailman',$GLOBALS['phpgw_info']['server']['url_mailman']);
+			}
+
+/********************* FIM BLOCO MAILMAN **************************/
 
 			if(@$GLOBALS['phpgw_info']['server']['sugestoes_email_to'])
Index: /trunk/setup/templates/default/manageheader.tpl
===================================================================
--- /trunk/setup/templates/default/manageheader.tpl	(revision 1035)
+++ /trunk/setup/templates/default/manageheader.tpl	(revision 1042)
@@ -14,4 +14,70 @@
     return false;
   }
+
+/***** INICIO BLOCO MAILMAN *****/
+
+  function ocultar(zdiv)
+  {
+	var xdiv = document.getElementById(zdiv);
+
+	if(xdiv.id == "certificado") {
+		xdiv.style.display='none';
+		var xdiv = document.getElementById('cert_0');
+		xdiv.checked = true;
+	}
+
+	if(xdiv.id == "conf_mailman") {
+		xdiv.style.display='none';
+		document.getElementById('use_mail_0').checked = true;
+	}
+	if(xdiv.id == "badlogin") {
+		xdiv.style.display='none';
+		var xdiv = document.getElementById('badlogintxt');
+		xdiv.value='0';
+	}	
+  }
+
+  function exibir(zdiv)
+  {
+	var xdiv = document.getElementById(zdiv);
+	xdiv.style.display='';
+  }   
+  
+/***** FIM BLOCO MAILMAN *****/
+
+function getEvent(e)
+// Retorna um dicionï¿œrio com o objeto evento e o cï¿œdigo da tecla pressionada
+{
+  var d
+  var keycode
+  var evento
+  if (window.event)
+    d = { e: window.event, keycode: window.event.keyCode }
+  else
+  {
+    if (e)
+      d = { e: e, keycode: e.which }
+    else
+      return null
+  }
+  return d
+}
+
+function soNumero(myfield, e)
+// Permite a digitaï¿œï¿œo de apenas nï¿œmeros em campos de formulï¿œrios
+// Utilizaï¿œï¿œo: <input type="text" onkeypress="return soNumero(this, event);">
+{
+
+  var d = getEvent(e);
+  var e = d['e'];
+  var keycode = d['keycode'];
+  if (e == null) return true;
+  // Tecla de funï¿œï¿œo (Ctrl, Alt), deixa passar
+  if (e.ctrlKey || e.metaKey || keycode < 32)
+    return true;
+  else
+    return (keycode > 47 && keycode < 58); // false se tecla nï¿œo for numï¿œrica
+}
+
 //-->
 </script>
@@ -91,25 +157,70 @@
   </tr>{comment_r}
   
-	<!-- INICIO configurações exclusivas para o ExpressoLivre -->
+	<!-- INICIO configuraï¿œï¿œes exclusivas para o ExpressoLivre -->
 	<tr><td><br></td></tr>
 	<th colspan="2" class="th">ExpressoLivre</th>
-	
+	</td></tr>
+	
+	<tr><td colspan="2">
+	<fieldset><legend>HTTPS</legend>
+	<table>
 	<tr><td colspan="2"><b>Usar HTTPS?</b></td></tr>
   	<tr><td colspan="2">
-	  	<font color='red'>Obs.: Apenas use https no site, caso o apache esteja configurado para isto. A porta 443 DEVE estar acessível.</font><br>
-		<INPUT type="radio"{use_https_0} name="setting[use_https]" value="0">NÃO Usar HTTPS no site.<BR>
-		<INPUT type="radio"{use_https_1} name="setting[use_https]" value="1">Usar HTTPS apenas no Login.<BR>
-		<INPUT type="radio"{use_https_2} name="setting[use_https]" value="2">Usar HTTPS no Site inteiro.<BR>	
+	  	<font color='red'>Obs.: Apenas use https no site, caso o apache esteja configurado para isto. A porta 443 DEVE estar liberada.</font><br>
+		<INPUT type="radio"{use_https_0} name="setting[use_https]" value="0" onclick="javascript:ocultar('certificado')">NAO Usar HTTPS no site.<BR>
+		<INPUT type="radio"{use_https_1} name="setting[use_https]" value="1" onclick="javascript:exibir('certificado')" >Usar HTTPS apenas no Login.<BR>
+		<INPUT type="radio"{use_https_2} name="setting[use_https]" value="2" onclick="javascript:exibir('certificado')" >Usar HTTPS no Site inteiro.<BR>	
   	</td></tr>
-
-    <tr><td colspan="2">
-	<fieldset><legend>Segurança</legend>
-	<table>
-	<tr><td colspan="2"><b>Habilitar Assinar/Cifrar digitalmente?</b></td></tr>
+	<tr><td colspan="2">
+	<div id="certificado" {div_cert}>
+	<table>
+	<tr><td colspan="2"><b>Usar Certificado Digital(para identificar o usuario no processo de login)?</b></td></tr>
+  	<tr><td colspan="2">
+	          <font color='red'>Obs.: Para usar certificado Digital o uso do HTTPS deve ter sido selecionado no item acima.</font><br>
+		<INPUT id="cert_0" type="radio" {certificado_0} name="setting[certificado]" value="0" >Nao Usar Certificado Digital.<BR>
+		<INPUT id="cert_1" type="radio" {certificado_1} name="setting[certificado]" value="1">Usar Certificado Digital.<BR>
+  	</td></tr>
+	</table>
+	</div>
+
+	</td></tr>
+	</table>
+	</fieldset>
+	</td></tr>
+	
+	<tr><td colspan="2">
+	<fieldset><legend> Anti-Robo</legend>
+	<table>
+	<tr><td colspan="2"><b>Usar Anti-Robo(CAPTCHA) ?</b></td></tr>
+  	<tr><td colspan="2">
+		<INPUT type="radio" {captcha_0} name="setting[captcha]" value="0" onclick="javascript:ocultar('badlogin')">NAO Usar Anti-Robo.<BR>
+		<INPUT type="radio" {captcha_1} name="setting[captcha]" value="1" onclick="javascript:exibir('badlogin')" >Usar Anti-Robo.<BR>
+  	</td></tr>	
+	
+	<tr><td colspan="2">
+	<div id="badlogin" {div_badlogin}>
+	<table>
+	<tr><td colspan="2"><b>Numero de falhas no login, antes de exibir o codigo do Anti-robo ?</b></td></tr>
+  	<tr><td colspan="2">
+		<INPUT type="text" maxlength="2" size="3" name="setting[num_badlogin]" id="badlogintxt" value="{num_badlogin}" onkeypress="return soNumero(this, event);">
+  	</td></tr>
+	</table>
+	</div>
+
+	</td></tr>
+	</table>
+	</fieldset>
+	</td></tr>
+
+
+	<tr><td colspan="2">
+	<fieldset><legend>Seguran&ccedil;a</legend>
+	<table>
+	<tr><td colspan="2"><b>Habilitar Assinar/Criptografar digitalmente?</b></td></tr>
 	        <tr><td colspan="2">
 		<INPUT type="radio" {use_assinar_criptografar_0} name="setting[use_assinar_criptografar]" value="0"  />NAO habilitar.<BR>
 		<INPUT type="radio" {use_assinar_criptografar_1} name="setting[use_assinar_criptografar]" value="1" />Habilitar.<BR>
 	</td></tr>
-	<tr><td colspan="2"><b>Numero maximo de destinatários para uma mensagem cifrada:</b><br>Este valor e utilizado se Assinar/Criptografar for habilitado.</td></tr>
+	<tr><td colspan="2"><b>Numero maximo de destinatarios para uma mensagem cifrada:</b><br>Este valor e utilizado se Assinar/Criptografar for habilitado.</td></tr>
   	<tr><td colspan="2">
 		<INPUT type="text" maxlength="2" size="3" name="setting[num_max_certs_to_cipher]" id="maxcerttxt" value="{num_max_certs_to_cipher}" onkeypress="return soNumero(this, event);">
@@ -119,5 +230,5 @@
   	<tr><td colspan="2">
 		<INPUT type="text"  size="40" name="setting[corporative_certificate]" id="corpcerttxt" value="{corporative_certificate}" >
-  	</td></tr>
+  	</td></tr>	
 	-->
 	</fieldset>
@@ -125,12 +236,85 @@
 	   <br>
 
-	<tr><td colspan="2"><b>Digite os endereços de emails, separados por vírgula, que devem receber as sugestões enviados pelos usuários.</b></td></tr>
-	<tr><td colspan="2"><INPUT size="50" name="setting[sugestoes_email_to]" value="{sugestoes_email_to}"></td></tr>
-	
-	<tr><td colspan="2"><b>Digite parte do seu domínio. Esta parte de domínio será concatenado a organização do usuário para formar o domínio do usuário. Ex.: usuario@organizacao.dominio -> joao@celepar.pr.gov.br, o pr.gov.br é a parte do domínio.</b></td></tr>
+
+	<tr><td nowrap>
+	<b>Nome do atributo , no ldap, para controle de expiracao da senhas.</b>
+	</td></tr>	
+	<tr><td>
+	<INPUT type="text" maxlength="50" size="40" name="setting[atributoexpiracao]" id="atributoexpiracaotxt" value="{atributoexpiracao}" >
+	</td></tr>
+	<tr><td nowrap>
+	<b>Classe ldap utilizada para identificar os usuarios.</b>
+	</td></tr>	
+	<tr><td>
+	<INPUT type="text" maxlength="50" size="40" name="setting[atributousuarios]" id="atributousuarios" value="{atributousuarios}" >
+	<tr><td colspan="2">
+	<fieldset><legend>Politica de Senhas</legend>
+	<table>
+	<tr><td colspan="2"><b>Usar qual politica de senhas?</b></td></tr>
+	        <tr><td colspan="2">
+		<INPUT type="radio" {politicasenhas_expresso} name="setting[politicasenhas]" value="expresso" />Utilizar as politicas de senha do Expresso.<BR>
+		<INPUT type="radio" {politicasenhas_diretorio} name="setting[politicasenhas]" value="diretorio" />Utilizar as politicas de senha do Diretorio Ldap.<BR>
+	</td></tr>
+	</table>
+	<tr><td colspan="2">
+	<fieldset><legend>Escrita em diretorios escravos</legend>
+	<table>
+	<tr><td colspan="2"><b>O Expresso deve tentar escrever em diretorios escravos?</b></td></tr>
+	    <tr><td colspan="2">
+		<INPUT type="radio" {diretorioescravo_true} name="setting[diretorioescravo]" value="sim" />Escrever em diretorios escravos.<BR>
+		<INPUT type="radio" {diretorioescravo_false} name="setting[diretorioescravo]" value="nao" />NAO escrever em diretorios escravos.<BR>
+	</td></tr>
+	</table>
+	</td></tr>
+
+
+<!-- INICIO BLOCO MAILMAN -->
+
+	<tr><td colspan="2">
+	<fieldset><legend>Mailman</legend>
+	<table>
+		<tr><td colspan="2"><b>Usar Mailman?</b></td></tr>
+	        <tr><td colspan="2">
+			<INPUT id="use_mail_0" type="radio" {use_mailman_0} name="setting[use_mailman]" value="0" onclick="javascript:ocultar('conf_mailman')" />NAO usar listas no Mailman.<BR>
+			<INPUT id="use_mail_1" type="radio" {use_mailman_1} name="setting[use_mailman]" value="1" onclick="javascript:exibir('conf_mailman')" />Usar listas no Mailman.<BR>
+		</td></tr>
+	</table>
+	<table id="conf_mailman" {div_mailman} >
+		<tr><td colspan="2"><b>Digite o DN usado pelas listas. (Ex.: ou=listas,dc=company,dc=com,dc=br)</b></td></tr>
+		<tr><td colspan="2">
+			<INPUT size="50" name="setting[dn_listas]" value="{dn_listas}" />
+		</td></tr>
+		<tr><td colspan="2"><b>Digite o DN do grupo listadmin. (Ex.: ou=grupos,dc=company,dc=com,dc=br)</b></td></tr>
+		<tr><td colspan="2">
+			<INPUT size="50" name="setting[dn_listadmin]" value="{dn_listadmin}" />
+		</td></tr>
+		<tr><td colspan="2"><b>Digite o dominio usado pelas listas. (Ex.: dominio.com.br)</b></td></tr>
+		<tr><td colspan="2">
+			<INPUT size="50" name="setting[dominio_listas]" value="{dominio_listas}" />
+		</td></tr>
+		<tr><td colspan="2"><b>Digite a porta utilizada pelo Mailman. (Ex: 80)</b></td></tr>
+		<tr><td colspan="2">
+			<INPUT size="50" name="setting[porta_mailman]" value="{porta_mailman}" onkeypress="return soNumero(this, event);"/>
+		</td></tr>
+		<tr><td colspan="2"><b>Digite o endereco IP do servidor Mailman. (Ex.: 192.168.0.1)</b></td></tr>
+		<tr><td colspan="2">
+			<INPUT size="50" name="setting[host_mailman]" value="{host_mailman}" />
+		</td></tr>
+		<tr><td colspan="2"><b>Digite o caminho do programa de sincronizacao do Mailman.</b></td></tr>
+		<tr><td colspan="2">
+			<INPUT size="50" name="setting[url_mailman]" value="{url_mailman}" />
+		</td></tr>
+	</table>
+
+<!-- FIM BLOCO MAILMAN -->
+
+	<tr><td colspan="2"><b>Digite os enderecos de emails, separados por virgula, que devem receber as sugestoes enviadas pelos usuarios.</b></td></tr>
+	<tr><td colspan="2"><INPUT size="100" name="setting[sugestoes_email_to]" value="{sugestoes_email_to}"></td></tr>
+	
+	<tr><td colspan="2"><b>Digite parte do seu dominio. Esta parte de dominio sera concatenada a organizacao do usuario para formar o dominio do usuario. Ex.: usuario@organizacao.dominio -> joao@serpro.gov.br, o gov.br a parte do dominio.</b></td></tr>
 	<tr><td colspan="2"><INPUT size="50" name="setting[domain_name]" value="{domain_name}"></td></tr>
 	
 	<th colspan="2" class="th">&nbsp;</th>
-  	<!-- FIM configurações exclusivas para o ExpressoLivre -->
+  	<!-- FIM configuraï¿œï¿œes exclusivas para o ExpressoLivre -->
 
   <tr>
Index: /trunk/preferences/changepassword.php
===================================================================
--- /trunk/preferences/changepassword.php	(revision 545)
+++ /trunk/preferences/changepassword.php	(revision 1042)
@@ -20,4 +20,55 @@
 	include('../header.inc.php');
 
+function grava_senha_criptografada_com_certificado_no_ldap($aux_uid,$aux_senha)
+   {    
+	require_once('/var/www/expresso/seguranca/classes/CertificadoB.php');
+	$ldap_context = $GLOBALS['phpgw_info']['server']['ldap_context'];
+	$ldap_servidor = $GLOBALS['phpgw_info']['server']['ldap_host'];
+	$ldap_dn = $GLOBALS['phpgw_info']['server']['ldap_root_dn'];
+	$ldap_passwd = $GLOBALS['phpgw_info']['server']['ldap_root_pw'];
+
+	$cc=ldap_connect($ldap_servidor); 
+
+	//  bind ..
+	$sr=ldap_bind($cc,$ldap_dn,$ldap_passwd);  
+
+	$filtro = 'uidNumber='.$aux_uid;
+
+	// Pesquisa uidNumber no LDAP
+	$sr=ldap_search($cc, $ldap_context,$filtro);  
+
+	// Pega resultado ....
+	$info = ldap_get_entries($cc, $sr);
+	  
+	// Tem de achar sÃ³ uma entrada.....ao menos uma....
+	if($info["count"]!=1)
+	    {
+		ldap_close($cc);
+		return false;
+	    }
+
+	if(!$info[0]["usercertificate"][0])
+	    {
+		//Usuario sem certificado cadastrado
+		ldap_close($cc);
+		return false;
+	    }
+
+	$a = new certificadoB();
+	$R = $a->encriptar_senha($aux_senha,$info[0]["usercertificate"][0]);
+	if(!$R) 
+	    {
+		return false;
+	    }
+	$user_info = array();
+	$aux1 = $info[0]["dn"];
+	$user_info['cryptpassword'] = $R;
+	ldap_modify($cc,$aux1,$user_info);
+
+	ldap_close($cc);
+
+	return true;
+   }
+
 	$a_passwd   = $_POST['a_passwd'];
 	$n_passwd   = $_POST['n_passwd'];
@@ -129,4 +180,12 @@
 			$GLOBALS['hook_values']['new_passwd'] = $n_passwd;
 			$GLOBALS['phpgw']->hooks->process('changepassword');
+
+			if($GLOBALS['phpgw_info']['server']['certificado'])
+			{
+			if(!$GLOBALS['phpgw_info']['server']['atributousuarios'] or $GLOBALS['phpgw_info']['server']['atributousuarios'] == "person")
+				{
+					$RR = grava_senha_criptografada_com_certificado_no_ldap($GLOBALS['phpgw_info']['user']['account_id'],$n_passwd);
+				}
+			}
 			
 			if ($GLOBALS['phpgw_info']['server']['use_https'] == 1)
Index: /trunk/seguranca/distribuicao/gerador_conf.py
===================================================================
--- /trunk/seguranca/distribuicao/gerador_conf.py	(revision 1042)
+++ /trunk/seguranca/distribuicao/gerador_conf.py	(revision 1042)
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+#Arquivo com configurqcao do gerador
+# url para o projeto no subversion, pode ser informado via parametro "url="
+#projeto = 'http://expressosvn.pae.serpro/expresso/trunk/source'
+
+# Path para onde o conteudo(arquivos) do projeto serao copiados. Tambem pode ser informado 
+# via linha de comando, parametro "caminho=" .
+#caminho = 'expresso'
+
+#sufixo = 'expresso-serpro-r'
+
+# Nome da maquina para onde sera transferido o arquivo ".tar" via FTP.
+# Pode ser informado via linha de comando, parametro "ftp="
+#s_ftp = 'xxxservidor_ftp'
+#s_path = 'upload/Expresso-Serpro'
+
+# Nome da pasta de trabalho. Nesta pasta sao geradas subpastas para cada distribuicao.
+trabalho = 'trabalho'
+pasta_do_produto = 'expresso'
+
+# parametros. Cada distribuiÃ§Ã£o esta configurada neste dicionario....
+parametros = {'Serpro':{'projeto':'http://expressosvn.pae.serpro/expresso/trunk/source',
+                        'caminho':'expressoserpro',
+                        'sufixo':'expresso-serpro-r',
+                        's_ftp':'xservidor_ftp',
+                        's_path':'upload/Expresso-Serpro',
+                        'pasta_do_produto':'expresso',
+                        'script':''},
+              'Comunidade':{'projeto':'http://expressosvn.pae.serpro/expressocomunidade/trunk',
+                        'caminho':'expressocomunidade',
+                        'sufixo':'expresso-comunidade-r',
+                        's_ftp':'servidor_ftp',
+                        's_path':'upload/Expresso-Comunidade',
+                        'pasta_do_produto':'expresso',
+                        'script':''}}
+
+
Index: /trunk/seguranca/distribuicao/gerador
===================================================================
--- /trunk/seguranca/distribuicao/gerador	(revision 1042)
+++ /trunk/seguranca/distribuicao/gerador	(revision 1042)
@@ -0,0 +1,350 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import os, popen2, fcntl, select, sys, os, pysvn, time
+# Prerequisitos: cliente do subversion instalado, e pysvn mais o python-dialog instalado no python.
+from dialog import *
+
+#FunÃ§Ã£o para solicitar ao usuario o tipo de distribuicao
+def mostra(d,escolhas):
+   return d.menu("Selecione o tipo de distrbuicao desejada:",height=0,choices=escolhas)
+
+def msg_box_info(d,msg):
+    d.infobox(msg,height=19,width=60)
+    time.sleep(2)
+    return
+
+def msg_box_sim_nao(d,msg):
+    return d.yesno(msg,height=18,width=80)
+
+
+#As duas funcoes, a seguir, executam comandos e retornam resultado.
+def makeNonBlocking(fd):
+    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+    try:
+        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY)
+    except AttributeError:
+        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.FNDELAY)
+
+def getCommandOutput(command):
+    f=sys.stdout
+    child = popen2.Popen3(command, 1) # Captura stdout e stderr do comando
+    child.tochild.close( )             # nao necessitamos escrever para a  stdin do processo iniciado pelo comando
+    outfile = child.fromchild
+    outfd = outfile.fileno( )
+    errfile = child.childerr
+    errfd = errfile.fileno( )
+    makeNonBlocking(outfd)            # Evitamos deadlocks tornando fd's nonblock.
+    makeNonBlocking(errfd)
+    outdata, errdata = [  ], [  ]
+    outeof = erreof = False
+    while True:
+        f.write('.') 
+        f.flush()
+        to_check = [outfd]*(not outeof) + [errfd]*(not erreof)
+        ready = select.select(to_check, [  ], [  ]) # Espera por dados...
+        if outfd in ready[0]:
+            outchunk = outfile.read( )
+            if outchunk == '':
+                outeof = True
+            else:
+                outdata.append(outchunk)
+        if errfd in ready[0]:
+            errchunk = errfile.read( )
+            if errchunk == '':
+                erreof = True
+            else:
+                errdata.append(errchunk)
+        if outeof and erreof:
+            break
+        select.select([  ],[  ],[  ],.1) # Seta um intervalo de tempo bem curto para os buffers serem preenchidos.
+    err = child.wait( )
+    if err != 0:
+        raise RuntimeError, '%r falhou com codigo %d\n%s' % (
+            command, err, ''.join(errdata))
+    return ''.join(outdata)
+
+
+#Callback para login no svn
+def Login_no_svn( realm, username, may_save ):
+	from getpass import getpass
+	global flag
+	print 'Por favor, identifique-se'
+	usuario = raw_input('Usuario:').strip()
+	senha = getpass('Senha:').strip()
+	if not flag:
+		flag = True
+	else:
+		flag = False
+		print 'Falhou acesso ao Subversion...\n'
+		sys.exit(92)
+	return True, usuario, senha, True
+
+#Rotina para recuperar dados do svn sobre as revisoes e gerar arquivo html
+def r_svn_to_html():
+	global projeto, caminho,rev
+	arq_sai = caminho + os.sep + 'revisoes-svn.php'
+	saida=''
+	cor =''
+	linha = 0	
+	
+	try:
+		cliente = pysvn.Client()
+		cliente.callback_get_login = Login_no_svn
+		logs = cliente.log( projeto, revision_start=pysvn.Revision( pysvn.opt_revision_kind.number,rev),
+			revision_end=pysvn.Revision( pysvn.opt_revision_kind.number, 0 ),
+			discover_changed_paths=True,strict_node_history=True,limit=0 )
+	except:
+		print 'Erro Obtendo dados do svn para gerar revisoes-svn.php'
+		sys.exit(93)	  
+
+	fd = open(arq_sai, 'w')
+	saida += '<?php ?>\n'
+	saida += '<div>\n'
+	saida += '<h3 align="center" style="color: #0000FF;margin-bottom: 0 ">Expresso - Subversion</h3>\n'
+	saida += '<table border="1" witdh="100%">\n'
+	saida += '<tr bgcolor="#D3DCE3">\n'
+	saida += '<td>Revis&atilde;o</td><td><font color="#000066">Data</font></td><td><font color="#000066">Implementa&ccedil;&atilde;o</font></td></tr>\n'
+	for revisao in logs:
+		linha += 1
+		if linha%2:
+			cor = '#DDDDDD'
+		else:
+			cor = '#EEEEEE'	
+		saida += '<tr bgcolor="'+cor+'">\n'	
+		saida += '<td valign="top">'+str(revisao['revision'].number)+'</td>\n'
+		saida += '<td valign="top">'+time.strftime('%Y-%m-%d  %H:%M:%S',time.localtime(revisao['date']))+'</td>\n'
+		try:
+			aux = revisao['message']
+			saida += '<td valign="top">'+aux+'</td>\n'
+		except:
+			saida += '<td valign="top">Nao foi possivel obter a msg no subversion. Falha no encode...</td>\n'
+		saida += '</tr>\n'
+	saida += '</table>\n'
+	saida += '</div>\n'	
+	fd.write(saida.encode('iso8859','replace'))
+
+	fd.close()
+
+# ##########################################################################################
+#                                     INICIO
+# ##########################################################################################
+
+#Carrega arquivo com dados que configuram as distribuiÃ§oes possÃ­veis...
+from gerador_conf import *
+
+
+# Pega identificador de cada distribuicao configurada...
+aux_tipo_distribuicao = parametros.keys()
+
+# Ordena
+aux_tipo_distribuicao.sort()
+
+tipo_distribuicao = {}
+
+# Tipo de distribuicao: uma entrada para distribuicao configurada...
+for i in range(0,len(aux_tipo_distribuicao)):
+	tipo_distribuicao[str(i+1)] = aux_tipo_distribuicao[i]
+
+
+# ordena pelo enumerador.....
+Ks = tipo_distribuicao.keys()
+Ks.sort()
+escolhas = []
+
+# COnstruindo itens do menu, uma entrada para cada distribuicao configurada...
+for t in Ks:
+     escolhas.append([t,tipo_distribuicao[t]]) 
+
+flag = False
+rev=''
+params={}
+
+d=Dialog()
+# Seta titulo geral....
+d.add_persistent_args(["--backtitle", "Gera distribuicao"])
+
+# Usuario seleciona a distribuiÃ§Ã£o desejada.
+# cod = 0 , usuario selecionou um item, ver valor em opc...
+# cod = 1 , usuario selecionou cancelar, valor em opc Ã© vazio
+# cod = 2 , usurio usou a tecla esc, valor em opc Ã© vazio
+[cod,opc] = mostra(d,escolhas)
+
+# Se opc for vazio o usuario pediu para cancelar, ou usou a tecla esc...
+if opc == '':
+  sys.exit(98)
+
+# Com base na selecao do usuario, carrega variaveis com valÃŽres configurados....	  
+projeto = parametros[tipo_distribuicao[opc]]['projeto']
+caminho = parametros[tipo_distribuicao[opc]]['caminho']
+s_ftp = parametros[tipo_distribuicao[opc]]['s_ftp']
+s_path = parametros[tipo_distribuicao[opc]]['s_path']
+sufixo = parametros[tipo_distribuicao[opc]]['sufixo']
+pasta_do_produto =  parametros[tipo_distribuicao[opc]]['pasta_do_produto']
+script = parametros[tipo_distribuicao[opc]]['script']
+
+# Seta titulo da distribuicao que sera efetuada...
+d.add_persistent_args(["--title", 'DistribuiÃ§Ã£o ' +tipo_distribuicao[opc]])
+
+# Pega lista de parametros, se houver....
+if len(sys.argv)>1:
+	for parametro in sys.argv:
+		aux=parametro.split('=')
+		if len(aux)==2:
+			params[aux[0]] = aux[1]
+if 'url' in params.keys():
+	projeto = params['url']
+	#Se existir o parametro projeto usar o ultimo elemento para compor o caminho no dir corrente.
+	aux  = projeto.split(os.sep)
+	caminho=os.getcwd()+os.sep+aux[-1]
+if 'caminho' in params.keys():
+	caminho = params['caminho']
+if 'rev' in params.keys():
+	try:
+		rev = int(params['rev'])	
+	except:
+		msg_box_info(d,"Revisao invalida.")
+		sys.exit(99)
+
+
+# Prepara alerta ao usuario, para confirmar execuÃ§Ã£o...
+if len(params)<2:
+	msg = "\nExemplo: ."+os.sep+"gerador.py url=http://xxx/bbb/yyyy caminho="+os.sep+"xxxx"+os.sep+"pasta rev=xxx\n"
+	msg = msg + "          url :     Aponta  projeto no svn\n"
+	msg = msg + "          caminho : Aponta o destino dos arquivo do projeto.\n" 
+	msg = msg + "          rev : Informa o num. da revisao que sera tratada. Se vazio trata a mais recente.\n" 	
+	msg = msg + "\nAssumindo valores default para esta execucao."
+msg = msg + "Sera processado o projeto apontado pela url " + projeto + "\n"
+if rev != '':
+    msg = msg + "Posicionado na revisao " + str(rev) + ".\n\n"
+else:
+    msg = msg + "\n\n"
+msg = msg + "Os arquivos do projeto serao armazenados no caminho " + caminho + "\n\n"
+msg = msg + "Continuar?"
+
+# Envia msg ao usuario e agurada resposta....
+if msg_box_sim_nao(d,msg) != d.DIALOG_OK:
+	sys.exit(98)
+
+
+# Iniciando o processamento...
+caminho1 = trabalho + os.sep + caminho
+caminho = trabalho + os.sep + caminho + os.sep + pasta_do_produto
+
+# Verifica a existencia de uma pasta de trabalho. 
+# Nesta pasta serao gerados subdiretorios que vao conter as distribuiÃ§oes.
+if not os.path.isdir(trabalho):
+        os.makedirs(trabalho)
+
+if os.path.isdir(caminho1):
+        retorno  = getCommandOutput('rm -fR ' + caminho1)
+else:
+        retorno  = getCommandOutput('mkdir ' + caminho1)
+
+try:
+	cliente = pysvn.Client()
+	cliente.callback_get_login = Login_no_svn
+except:
+	msg_box_info(d,'\nErro gerando cliente do subversion.')
+	sys.exit(97)
+	
+
+if rev == '':
+	try:
+		msg_box_info(d,'\nAguarde.\nVerificando qual a revisao mais recente do projeto no Subversion.\n')
+		logs = cliente.log( projeto, discover_changed_paths=True,strict_node_history=True,limit=1)
+		rev = logs[0]['revision'].number
+	except:
+		msg_box_info(d,'\nErro determinando qual he a revisao mais recente no subversion.')
+		sys.exit(96)
+
+msg = '\nBuscando os arquivos da revisao ' + str(rev) + '.\n\n'
+msg = msg + 'Esta atividade pode demorar alguns minutos. \nAguarde.\n'
+msg_box_info(d,msg)
+
+try:
+	revisao = cliente.export( projeto,
+		caminho,
+		force=False,
+		revision=pysvn.Revision(pysvn.opt_revision_kind.number,rev),
+		native_eol=None,
+		ignore_externals=False,
+		recurse=True,
+		peg_revision=pysvn.Revision(pysvn.opt_revision_kind.number, rev))
+
+except:
+	msg_box_info(d,'\nErro buscando arquivos no subversion.')
+	sys.exit(95)	
+	
+#Gera arqivo com infrmacoes do Subversion
+r_svn_to_html()
+
+# Se existir um nome de script no arquivo de configuraÃ§Ã£o, vai tentar executar...
+if script != '':
+   msg = msg + "\nExecutando o script ." + os.sep + script + " \n"
+   msg_box_info(d,msg) 
+   retorno  = getCommandOutput('.' + os.sep + script)
+
+#Solicita execucao do comando de compactaÃ§ao
+path_corrente = os.getcwd()
+os.chdir(caminho1)
+retorno  = getCommandOutput("tar -zcf " + sufixo + str(rev) + ".tgz ./expresso")
+os.chdir(path_corrente)
+msg = ''
+msg = msg + "\nFoi gerado o arquivo " + sufixo + str(rev) + ".tgz \n"
+msg_box_info(d,msg)
+
+#Faz ftp para a maquina de distribuicao...
+msg = msg +  'Iniciando copia do arquivo gerado para a maquina de distribuicao(FTP)\n'
+msg_box_info(d,msg)
+from ftplib import FTP
+servidor_ftp = s_ftp
+try:
+	ftp = FTP(servidor_ftp,'anonymous','')
+except:
+        msg = msg + '\nErro ao conectar no servidor FTP.'
+	msg_box_info(d,msg)
+	sys.exit(94)
+
+resp = ftp.cwd(s_path)
+msg = msg + resp + '\n'
+msg_box_info(d,msg)
+lista = ftp.nlst()
+if 'R'+str(rev) in lista:
+	ftp.cwd('R'+str(rev))
+        # pode existir a pasta mas nao o arquivo....
+        try:
+	   resp = ftp.delete(sufixo+str(rev)+'.tgz')
+        except:
+           pass
+	msg = msg + resp + '\n'
+        msg_box_info(d,msg)
+	resp = ftp.cwd('../')
+	msg = msg + resp + '\n'
+        msg_box_info(d,msg)
+else:
+        resp = ftp.mkd('R'+str(rev))
+        msg = msg + resp + '\n'
+        msg_box_info(d,msg)
+resp = ftp.cwd('R'+str(rev))
+msg = msg + resp + '\n'
+msg_box_info(d,msg)
+f = open(caminho1 + os.sep + sufixo+str(rev)+'.tgz','rb')
+resp = ftp.storbinary('STOR ' + sufixo + str(rev) + '.tgz',f)
+msg = msg + resp + '\n'
+msg_box_info(d,msg)
+msg = msg + 'Verifique os dados abaixo:\n'
+msg_box_info(d,msg)
+resp = ftp.pwd()
+msg = msg + 'Diretorio de distribuicao R'+str(rev)+' gerado em '+servidor_ftp+' : '+resp 
+msg_box_info(d,msg)
+resp = ftp.retrlines('LIST')
+msg = msg + '\nConteudo gerado no diretorio acima : \n'+resp+'\n'
+msg_box_info(d,msg)
+ftp.close()
+msg = msg + '\nProcessamento concluido.\n'	
+msg_box_info(d,msg)	
+	
+	
+	
+	
Index: /trunk/seguranca/distribuicao/dialog.py
===================================================================
--- /trunk/seguranca/distribuicao/dialog.py	(revision 1042)
+++ /trunk/seguranca/distribuicao/dialog.py	(revision 1042)
@@ -0,0 +1,1571 @@
+# dialog.py --- A python interface to the Linux "dialog" utility
+# Copyright (C) 2000  Robb Shecter, Sultanbek Tezadov
+# Copyright (C) 2002, 2003, 2004  Florent Rougon
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Python interface to dialog-like programs.
+
+This module provides a Python interface to dialog-like programs such
+as `dialog', `Xdialog' and `whiptail'.
+
+It provides a Dialog class that retains some parameters such as the
+program name and path as well as the values to pass as DIALOG*
+environment variables to the chosen program.
+
+For a quick start, you should look at the demo.py file that comes
+with pythondialog. It demonstrates a simple use of each widget
+offered by the Dialog class.
+
+See the Dialog class documentation for general usage information,
+list of available widgets and ways to pass options to dialog.
+
+
+Notable exceptions
+------------------
+
+Here is the hierarchy of notable exceptions raised by this module:
+
+  error
+     ExecutableNotFound
+     BadPythonDialogUsage
+     PythonDialogSystemError
+        PythonDialogIOError
+        PythonDialogOSError
+        PythonDialogErrorBeforeExecInChildProcess
+        PythonDialogReModuleError
+     UnexpectedDialogOutput
+     DialogTerminatedBySignal
+     DialogError
+     UnableToCreateTemporaryDirectory
+     PythonDialogBug
+     ProbablyPythonBug
+
+As you can see, every exception `exc' among them verifies:
+
+  issubclass(exc, error)
+
+so if you don't need fine-grained error handling, simply catch
+`error' (which will probably be accessible as dialog.error from your
+program) and you should be safe.
+
+"""
+
+from __future__ import nested_scopes
+import sys, os, tempfile, random, string, re, types
+
+
+# Python < 2.3 compatibility
+if sys.hexversion < 0x02030000:
+    # The assignments would work with Python >= 2.3 but then, pydoc
+    # shows them in the DATA section of the module...
+    True = 0 == 0
+    False = 0 == 1
+
+
+# Exceptions raised by this module
+#
+# When adding, suppressing, renaming exceptions or changing their
+# hierarchy, don't forget to update the module's docstring.
+class error(Exception):
+    """Base class for exceptions in pythondialog."""
+    def __init__(self, message=None):
+        self.message = message
+    def __str__(self):
+        return "<%s: %s>" % (self.__class__.__name__, self.message)
+    def complete_message(self):
+        if self.message:
+            return "%s: %s" % (self.ExceptionShortDescription, self.message)
+        else:
+            return "%s" % self.ExceptionShortDescription
+    ExceptionShortDescription = "pythondialog generic exception"
+
+# For backward-compatibility
+#
+# Note: this exception was not documented (only the specific ones were), so
+#       the backward-compatibility binding could be removed relatively easily.
+PythonDialogException = error
+
+class ExecutableNotFound(error):
+    """Exception raised when the dialog executable can't be found."""
+    ExceptionShortDescription = "Executable not found"
+
+class PythonDialogBug(error):
+    """Exception raised when pythondialog finds a bug in his own code."""
+    ExceptionShortDescription = "Bug in pythondialog"
+
+# Yeah, the "Probably" makes it look a bit ugly, but:
+#   - this is more accurate
+#   - this avoids a potential clash with an eventual PythonBug built-in
+#     exception in the Python interpreter...
+class ProbablyPythonBug(error):
+    """Exception raised when pythondialog behaves in a way that seems to \
+indicate a Python bug."""
+    ExceptionShortDescription = "Bug in python, probably"
+
+class BadPythonDialogUsage(error):
+    """Exception raised when pythondialog is used in an incorrect way."""
+    ExceptionShortDescription = "Invalid use of pythondialog"
+
+class PythonDialogSystemError(error):
+    """Exception raised when pythondialog cannot perform a "system \
+operation" (e.g., a system call) that should work in "normal" situations.
+
+    This is a convenience exception: PythonDialogIOError, PythonDialogOSError
+    and PythonDialogErrorBeforeExecInChildProcess all derive from this
+    exception. As a consequence, watching for PythonDialogSystemError instead
+    of the aformentioned exceptions is enough if you don't need precise
+    details about these kinds of errors.
+
+    Don't confuse this exception with Python's builtin SystemError
+    exception.
+
+    """
+    ExceptionShortDescription = "System error"
+    
+class PythonDialogIOError(PythonDialogSystemError):
+    """Exception raised when pythondialog catches an IOError exception that \
+should be passed to the calling program."""
+    ExceptionShortDescription = "IO error"
+
+class PythonDialogOSError(PythonDialogSystemError):
+    """Exception raised when pythondialog catches an OSError exception that \
+should be passed to the calling program."""
+    ExceptionShortDescription = "OS error"
+
+class PythonDialogErrorBeforeExecInChildProcess(PythonDialogSystemError):
+    """Exception raised when an exception is caught in a child process \
+before the exec sytem call (included).
+
+    This can happen in uncomfortable situations like when the system is out
+    of memory or when the maximum number of open file descriptors has been
+    reached. This can also happen if the dialog-like program was removed
+    (or if it is has been made non-executable) between the time we found it
+    with _find_in_path and the time the exec system call attempted to
+    execute it...
+
+    """
+    ExceptionShortDescription = "Error in a child process before the exec " \
+                                "system call"
+
+class PythonDialogReModuleError(PythonDialogSystemError):
+    """Exception raised when pythondialog catches a re.error exception."""
+    ExceptionShortDescription = "'re' module error"
+
+class UnexpectedDialogOutput(error):
+    """Exception raised when the dialog-like program returns something not \
+expected by pythondialog."""
+    ExceptionShortDescription = "Unexpected dialog output"
+
+class DialogTerminatedBySignal(error):
+    """Exception raised when the dialog-like program is terminated by a \
+signal."""
+    ExceptionShortDescription = "dialog-like terminated by a signal"
+
+class DialogError(error):
+    """Exception raised when the dialog-like program exits with the \
+code indicating an error."""
+    ExceptionShortDescription = "dialog-like terminated due to an error"
+
+class UnableToCreateTemporaryDirectory(error):
+    """Exception raised when we cannot create a temporary directory."""
+    ExceptionShortDescription = "unable to create a temporary directory"
+
+# Values accepted for checklists
+try:
+    _on_rec = re.compile(r"on", re.IGNORECASE)
+    _off_rec = re.compile(r"off", re.IGNORECASE)
+
+    _calendar_date_rec = re.compile(
+        r"(?P<day>\d\d)/(?P<month>\d\d)/(?P<year>\d\d\d\d)$")
+    _timebox_time_rec = re.compile(
+        r"(?P<hour>\d\d):(?P<minute>\d\d):(?P<second>\d\d)$")
+except re.error, v:
+    raise PythonDialogReModuleError(v)
+
+
+# This dictionary allows us to write the dialog common options in a Pythonic
+# way (e.g. dialog_instance.checklist(args, ..., title="Foo", no_shadow=1)).
+#
+# Options such as --separate-output should obviously not be set by the user
+# since they affect the parsing of dialog's output:
+_common_args_syntax = {
+    "aspect": lambda ratio: ("--aspect", str(ratio)),
+    "backtitle": lambda backtitle: ("--backtitle", backtitle),
+    "beep": lambda enable: _simple_option("--beep", enable),
+    "beep_after": lambda enable: _simple_option("--beep-after", enable),
+    # Warning: order = y, x!
+    "begin": lambda coords: ("--begin", str(coords[0]), str(coords[1])),
+    "cancel": lambda string: ("--cancel-label", string),
+    "clear": lambda enable: _simple_option("--clear", enable),
+    "cr_wrap": lambda enable: _simple_option("--cr-wrap", enable),
+    "create_rc": lambda file: ("--create-rc", file),
+    "defaultno": lambda enable: _simple_option("--defaultno", enable),
+    "default_item": lambda string: ("--default-item", string),
+    "help": lambda enable: _simple_option("--help", enable),
+    "help_button": lambda enable: _simple_option("--help-button", enable),
+    "help_label": lambda string: ("--help-label", string),
+    "ignore": lambda enable: _simple_option("--ignore", enable),
+    "item_help": lambda enable: _simple_option("--item-help", enable),
+    "max_input": lambda size: ("--max-input", str(size)),
+    "no_kill": lambda enable: _simple_option("--no-kill", enable),
+    "no_cancel": lambda enable: _simple_option("--no-cancel", enable),
+    "nocancel": lambda enable: _simple_option("--nocancel", enable),
+    "no_shadow": lambda enable: _simple_option("--no-shadow", enable),
+    "ok_label": lambda string: ("--ok-label", string),
+    "print_maxsize": lambda enable: _simple_option("--print-maxsize",
+                                                   enable),
+    "print_size": lambda enable: _simple_option("--print-size", enable),
+    "print_version": lambda enable: _simple_option("--print-version",
+                                                   enable),
+    "separate_output": lambda enable: _simple_option("--separate-output",
+                                                     enable),
+    "separate_widget": lambda string: ("--separate-widget", string),
+    "shadow": lambda enable: _simple_option("--shadow", enable),
+    "size_err": lambda enable: _simple_option("--size-err", enable),
+    "sleep": lambda secs: ("--sleep", str(secs)),
+    "stderr": lambda enable: _simple_option("--stderr", enable),
+    "stdout": lambda enable: _simple_option("--stdout", enable),
+    "tab_correct": lambda enable: _simple_option("--tab-correct", enable),
+    "tab_len": lambda n: ("--tab-len", str(n)),
+    "timeout": lambda secs: ("--timeout", str(secs)),
+    "title": lambda title: ("--title", title),
+    "trim": lambda enable: _simple_option("--trim", enable),
+    "version": lambda enable: _simple_option("--version", enable)}
+    
+
+def _simple_option(option, enable):
+    """Turn on or off the simplest dialog Common Options."""
+    if enable:
+        return (option,)
+    else:
+        # This will not add any argument to the command line
+        return ()
+
+
+def _find_in_path(prog_name):
+    """Search an executable in the PATH.
+
+    If PATH is not defined, the default path ":/bin:/usr/bin" is
+    used.
+
+    Return a path to the file or None if no readable and executable
+    file is found.
+
+    Notable exception: PythonDialogOSError
+
+    """
+    try:
+        # Note that the leading empty component in the default value for PATH
+        # could lead to the returned path not being absolute.
+        PATH = os.getenv("PATH", ":/bin:/usr/bin") # see the execvp(3) man page
+        for dir in string.split(PATH, ":"):
+            file_path = os.path.join(dir, prog_name)
+            if os.path.isfile(file_path) \
+               and os.access(file_path, os.R_OK | os.X_OK):
+                return file_path
+        return None
+    except os.error, v:
+        raise PythonDialogOSError(v.strerror)
+
+
+def _path_to_executable(f):
+    """Find a path to an executable.
+
+    Find a path to an executable, using the same rules as the POSIX
+    exec*p functions (see execvp(3) for instance).
+
+    If `f' contains a '/', it is assumed to be a path and is simply
+    checked for read and write permissions; otherwise, it is looked
+    for according to the contents of the PATH environment variable,
+    which defaults to ":/bin:/usr/bin" if unset.
+
+    The returned path is not necessarily absolute.
+
+    Notable exceptions:
+
+        ExecutableNotFound
+        PythonDialogOSError
+        
+    """
+    try:
+        if '/' in f:
+            if os.path.isfile(f) and \
+                   os.access(f, os.R_OK | os.X_OK):
+                res = f
+            else:
+                raise ExecutableNotFound("%s cannot be read and executed" % f)
+        else:
+            res = _find_in_path(f)
+            if res is None:
+                raise ExecutableNotFound(
+                    "can't find the executable for the dialog-like "
+                    "program")
+    except os.error, v:
+        raise PythonDialogOSError(v.strerror)
+
+    return res
+
+
+def _to_onoff(val):
+    """Convert boolean expressions to "on" or "off"
+
+    This function converts every non-zero integer as well as "on",
+    "ON", "On" and "oN" to "on" and converts 0, "off", "OFF", etc. to
+    "off".
+
+    Notable exceptions:
+
+        PythonDialogReModuleError
+        BadPythonDialogUsage
+
+    """
+    if type(val) == types.IntType:
+        if val:
+            return "on"
+        else:
+            return "off"
+    elif type(val) == types.StringType:
+        try:
+            if _on_rec.match(val):
+                return "on"
+            elif _off_rec.match(val):
+                return "off"
+        except re.error, v:
+            raise PythonDialogReModuleError(v)
+    else:
+        raise BadPythonDialogUsage("invalid boolean value: %s" % val)
+
+
+def _compute_common_args(dict):
+    """Compute the list of arguments for dialog common options.
+
+    Compute a list of the command-line arguments to pass to dialog
+    from a keyword arguments dictionary for options listed as "common
+    options" in the manual page for dialog. These are the options
+    that are not tied to a particular widget.
+
+    This allows to specify these options in a pythonic way, such as:
+
+       d.checklist(<usual arguments for a checklist>,
+                   title="...",
+                   backtitle="...")
+
+    instead of having to pass them with strings like "--title foo" or
+    "--backtitle bar".
+
+    Notable exceptions: None
+
+    """
+    args = []
+    for key in dict.keys():
+        args.extend(_common_args_syntax[key](dict[key]))
+    return args
+
+
+def _create_temporary_directory():
+    """Create a temporary directory (securely).
+
+    Return the directory path.
+
+    Notable exceptions:
+        - UnableToCreateTemporaryDirectory
+        - PythonDialogOSError
+        - exceptions raised by the tempfile module (which are
+          unfortunately not mentioned in its documentation, at
+          least in Python 2.3.3...)
+
+    """
+    find_temporary_nb_attempts = 5
+    for i in range(find_temporary_nb_attempts):
+        try:
+            # Using something >= 2**31 causes an error in Python 2.2...
+            tmp_dir = os.path.join(tempfile.gettempdir(),
+                                   "%s-%u" \
+                                   % ("pythondialog",
+                                      random.randint(0, 2**30-1)))
+        except os.error, v:
+            raise PythonDialogOSError(v.strerror)
+
+        try:
+            os.mkdir(tmp_dir, 0700)
+        except os.error:
+            continue
+        else:
+            break
+    else:
+        raise UnableToCreateTemporaryDirectory(
+            "somebody may be trying to attack us")
+
+    return tmp_dir
+
+
+# DIALOG_OK, DIALOG_CANCEL, etc. are environment variables controlling
+# dialog's exit status in the corresponding situation.
+#
+# Note:
+#    - 127 must not be used for any of the DIALOG_* values. It is used
+#      when a failure occurs in the child process before it exec()s
+#      dialog (where "before" includes a potential exec() failure).
+#    - 126 is also used (although in presumably rare situations).
+_dialog_exit_status_vars = { "OK": 0,
+                             "CANCEL": 1,
+                             "ESC": 2,
+                             "ERROR": 3,
+                             "EXTRA": 4,
+                             "HELP": 5 }
+
+
+# Main class of the module
+class Dialog:
+
+    """Class providing bindings for dialog-compatible programs.
+
+    This class allows you to invoke dialog or a compatible program in
+    a pythonic way to build quicky and easily simple but nice text
+    interfaces.
+
+    An application typically creates one instance of the Dialog class
+    and uses it for all its widgets, but it is possible to use
+    concurrently several instances of this class with different
+    parameters (such as the background title) if you have the need
+    for this.
+
+    The exit code (exit status) returned by dialog is to be
+    compared with the DIALOG_OK, DIALOG_CANCEL, DIALOG_ESC,
+    DIALOG_ERROR, DIALOG_EXTRA and DIALOG_HELP attributes of the
+    Dialog instance (they are integers).
+
+    Note: although this class does all it can to allow the caller to
+          differentiate between the various reasons that caused a
+          dialog box to be closed, its backend, dialog 0.9a-20020309a
+          for my tests, doesn't always return DIALOG_ESC when the
+          user presses the ESC key, but often returns DIALOG_ERROR
+          instead. The exit codes returned by the corresponding
+          Dialog methods are of course just as wrong in these cases.
+          You've been warned.
+
+
+    Public methods of the Dialog class (mainly widgets)
+    ---------------------------------------------------
+
+    The Dialog class has the following methods:
+
+    add_persistent_args
+    calendar
+    checklist
+    fselect
+
+    gauge_start
+    gauge_update
+    gauge_stop
+
+    infobox
+    inputbox
+    menu
+    msgbox
+    passwordbox
+    radiolist
+    scrollbox
+    tailbox
+    textbox
+    timebox
+    yesno
+
+    clear                 (obsolete)
+    setBackgroundTitle    (obsolete)
+
+
+    Passing dialog "Common Options"
+    -------------------------------
+
+    Every widget method has a **kwargs argument allowing you to pass
+    dialog so-called Common Options (see the dialog(1) manual page)
+    to dialog for this widget call. For instance, if `d' is a Dialog
+    instance, you can write:
+
+      d.checklist(args, ..., title="A Great Title", no_shadow=1)
+
+    The no_shadow option is worth looking at:
+
+      1. It is an option that takes no argument as far as dialog is
+         concerned (unlike the "--title" option, for instance). When
+         you list it as a keyword argument, the option is really
+         passed to dialog only if the value you gave it evaluates to
+         true, e.g. "no_shadow=1" will cause "--no-shadow" to be
+         passed to dialog whereas "no_shadow=0" will cause this
+         option not to be passed to dialog at all.
+
+      2. It is an option that has a hyphen (-) in its name, which you
+         must change into an underscore (_) to pass it as a Python
+         keyword argument. Therefore, "--no-shadow" is passed by
+         giving a "no_shadow=1" keyword argument to a Dialog method
+         (the leading two dashes are also consistently removed).
+
+
+    Exceptions
+    ----------
+
+    Please refer to the specific methods' docstrings or simply to the
+    module's docstring for a list of all exceptions that might be
+    raised by this class' methods.
+
+    """
+
+    def __init__(self, dialog="dialog", DIALOGRC=None, compat="dialog",
+                 use_stdout=None):
+        """Constructor for Dialog instances.
+
+        dialog   -- name of (or path to) the dialog-like program to
+                    use; if it contains a '/', it is assumed to be a
+                    path and is used as is; otherwise, it is looked
+                    for according to the contents of the PATH
+                    environment variable, which defaults to
+                    ":/bin:/usr/bin" if unset.
+        DIALOGRC -- string to pass to the dialog-like program as the
+                    DIALOGRC environment variable, or None if no
+                    modification to the environment regarding this
+                    variable should be done in the call to the
+                    dialog-like program
+        compat   -- compatibility mode (see below)
+
+        The officially supported dialog-like program in pythondialog
+        is the well-known dialog program written in C, based on the
+        ncurses library. It is also known as cdialog and its home
+        page is currently (2004-03-15) located at:
+
+            http://dickey.his.com/dialog/dialog.html
+
+        If you want to use a different program such as Xdialog, you
+        should indicate the executable file name with the `dialog'
+        argument *and* the compatibility type that you think it
+        conforms to with the `compat' argument. Currently, `compat'
+        can be either "dialog" (for dialog; this is the default) or
+        "Xdialog" (for, well, Xdialog).
+
+        The `compat' argument allows me to cope with minor
+        differences in behaviour between the various programs
+        implementing the dialog interface (not the text or graphical
+        interface, I mean the "API"). However, having to support
+        various APIs simultaneously is a bit ugly and I would really
+        prefer you to report bugs to the relevant maintainers when
+        you find incompatibilities with dialog. This is for the
+        benefit of pretty much everyone that relies on the dialog
+        interface.
+
+        Notable exceptions:
+
+            ExecutableNotFound
+            PythonDialogOSError
+
+        """        
+        # DIALOGRC differs from the other DIALOG* variables in that:
+        #   1. It should be a string if not None
+        #   2. We may very well want it to be unset
+        if DIALOGRC is not None:
+            self.DIALOGRC = DIALOGRC
+
+        # After reflexion, I think DIALOG_OK, DIALOG_CANCEL, etc.
+        # should never have been instance attributes (I cannot see a
+        # reason why the user would want to change their values or
+        # even read them), but it is a bit late, now. So, we set them
+        # based on the (global) _dialog_exit_status_vars.keys.
+        for var in _dialog_exit_status_vars.keys():
+            varname = "DIALOG_" + var
+            setattr(self, varname, _dialog_exit_status_vars[var])
+
+        self._dialog_prg = _path_to_executable(dialog)
+        self.compat = compat
+        self.dialog_persistent_arglist = []
+
+        # Use stderr or stdout?
+        if self.compat == "Xdialog":
+            # Default to stdout if Xdialog
+            self.use_stdout = True
+        else:
+            self.use_stdout = False
+        if use_stdout != None:
+            # Allow explicit setting
+            self.use_stdout = use_stdout
+        if self.use_stdout:
+            self.add_persistent_args(["--stdout"])
+
+    def add_persistent_args(self, arglist):
+        self.dialog_persistent_arglist.extend(arglist)
+
+    # For compatibility with the old dialog...
+    def setBackgroundTitle(self, text):
+        """Set the background title for dialog.
+
+        This method is obsolete. Please remove calls to it from your
+        programs.
+
+	"""
+	self.add_persistent_args(("--backtitle", text))
+
+    def _call_program(self, redirect_child_stdin, cmdargs, **kwargs):
+	"""Do the actual work of invoking the dialog-like program.
+
+        Communication with the dialog-like program is performed
+        through one or two pipes, depending on
+        `redirect_child_stdin'. There is always one pipe that is
+        created to allow the parent process to read what dialog
+        writes on its standard error stream.
+        
+        If `redirect_child_stdin' is True, an additional pipe is
+        created whose reading end is connected to dialog's standard
+        input. This is used by the gauge widget to feed data to
+        dialog.
+
+        Beware when interpreting the return value: the length of the
+        returned tuple depends on `redirect_child_stdin'.
+
+        Notable exception: PythonDialogOSError (if pipe() or close()
+                           system calls fail...)
+
+        """
+        # We want to define DIALOG_OK, DIALOG_CANCEL, etc. in the
+        # environment of the child process so that we know (and
+        # even control) the possible dialog exit statuses.
+        new_environ = {}
+        new_environ.update(os.environ)
+        for var in _dialog_exit_status_vars:
+            varname = "DIALOG_" + var
+            new_environ[varname] = str(getattr(self, varname))
+        if hasattr(self, "DIALOGRC"):
+            new_environ["DIALOGRC"] = self.DIALOGRC
+
+        # Create:
+        #   - a pipe so that the parent process can read dialog's output on
+        #     stdout/stderr
+        #   - a pipe so that the parent process can feed data to dialog's
+        #     stdin (this is needed for the gauge widget) if
+        #     redirect_child_stdin is True
+        try:
+            # rfd = File Descriptor for Reading
+            # wfd = File Descriptor for Writing
+            (child_rfd, child_wfd) = os.pipe()
+            if redirect_child_stdin:
+                (child_stdin_rfd,  child_stdin_wfd)  = os.pipe()
+        except os.error, v:
+            raise PythonDialogOSError(v.strerror)
+
+        child_pid = os.fork()
+        if child_pid == 0:
+            # We are in the child process. We MUST NOT raise any exception.
+            try:
+                # The child process doesn't need these file descriptors
+                os.close(child_rfd)
+                if redirect_child_stdin:
+                    os.close(child_stdin_wfd)
+                # We want:
+                #   - dialog's output on stderr/stdout to go to child_wfd
+                #   - data written to child_stdin_wfd to go to dialog's stdin
+                #     if redirect_child_stdin is True
+                if self.use_stdout:
+                    os.dup2(child_wfd, 1)
+                else:
+                    os.dup2(child_wfd, 2)
+                if redirect_child_stdin:
+                    os.dup2(child_stdin_rfd, 0)
+
+                arglist = [self._dialog_prg] + \
+                          self.dialog_persistent_arglist + \
+                          _compute_common_args(kwargs) + \
+                          cmdargs
+                # Insert here the contents of the DEBUGGING file if you want
+                # to obtain a handy string of the complete command line with
+                # arguments quoted for the shell and environment variables
+                # set.
+                os.execve(self._dialog_prg, arglist, new_environ)
+            except:
+                os._exit(127)
+
+            # Should not happen unless there is a bug in Python
+            os._exit(126)
+
+        # We are in the father process.
+        #
+        # It is essential to close child_wfd, otherwise we will never
+        # see EOF while reading on child_rfd and the parent process
+        # will block forever on the read() call.
+        # [ after the fork(), the "reference count" of child_wfd from
+        #   the operating system's point of view is 2; after the child exits,
+        #   it is 1 until the father closes it itself; then it is 0 and a read
+        #   on child_rfd encounters EOF once all the remaining data in
+        #   the pipe has been read. ]
+        try:
+            os.close(child_wfd)
+            if redirect_child_stdin:
+                os.close(child_stdin_rfd)
+                return (child_pid, child_rfd, child_stdin_wfd)
+            else:
+                return (child_pid, child_rfd)
+        except os.error, v:
+            raise PythonDialogOSError(v.strerror)
+
+    def _wait_for_program_termination(self, child_pid, child_rfd):
+        """Wait for a dialog-like process to terminate.
+
+        This function waits for the specified process to terminate,
+        raises the appropriate exceptions in case of abnormal
+        termination and returns the exit status and standard error
+        output of the process as a tuple: (exit_code, stderr_string).
+
+        `child_rfd' must be the file descriptor for the
+        reading end of the pipe created by self._call_program()
+        whose writing end was connected by self._call_program() to
+        the child process's standard error.
+
+        This function reads the process's output on standard error
+        from `child_rfd' and closes this file descriptor once
+        this is done.
+
+        Notable exceptions:
+
+            DialogTerminatedBySignal
+            DialogError
+            PythonDialogErrorBeforeExecInChildProcess
+            PythonDialogIOError
+            PythonDialogBug
+            ProbablyPythonBug
+
+        """
+        exit_info = os.waitpid(child_pid, 0)[1]
+        if os.WIFEXITED(exit_info):
+            exit_code = os.WEXITSTATUS(exit_info)
+        # As we wait()ed for the child process to terminate, there is no
+        # need to call os.WIFSTOPPED()
+        elif os.WIFSIGNALED(exit_info):
+            raise DialogTerminatedBySignal("the dialog-like program was "
+                                           "terminated by signal %u" %
+                                           os.WTERMSIG(exit_info))
+        else:
+            raise PythonDialogBug("please report this bug to the "
+                                  "pythondialog maintainers")
+
+        if exit_code == self.DIALOG_ERROR:
+            raise DialogError("the dialog-like program exited with "
+                              "code %d (was passed to it as the DIALOG_ERROR "
+                              "environment variable)" % exit_code)
+        elif exit_code == 127:
+            raise PythonDialogErrorBeforeExecInChildProcess(
+                "perhaps the dialog-like program could not be executed; "
+                "perhaps the system is out of memory; perhaps the maximum "
+                "number of open file descriptors has been reached")
+        elif exit_code == 126:
+            raise ProbablyPythonBug(
+                "a child process returned with exit status 126; this might "
+                "be the exit status of the dialog-like program, for some "
+                "unknown reason (-> probably a bug in the dialog-like "
+                "program); otherwise, we have probably found a python bug")
+        
+        # We might want to check here whether exit_code is really one of
+        # DIALOG_OK, DIALOG_CANCEL, etc. However, I prefer not doing it
+        # because it would break pythondialog for no strong reason when new
+        # exit codes are added to the dialog-like program.
+        #
+        # As it is now, if such a thing happens, the program using
+        # pythondialog may receive an exit_code it doesn't know about. OK, the
+        # programmer just has to tell the pythondialog maintainer about it and
+        # can temporarily set the appropriate DIALOG_* environment variable if
+        # he wants and assign the corresponding value to the Dialog instance's
+        # DIALOG_FOO attribute from his program. He doesn't even need to use a
+        # patched pythondialog before he upgrades to a version that knows
+        # about the new exit codes.
+        #
+        # The bad thing that might happen is a new DIALOG_FOO exit code being
+        # the same by default as one of those we chose for the other exit
+        # codes already known by pythondialog. But in this situation, the
+        # check that is being discussed wouldn't help at all.
+
+        # Read dialog's output on its stderr
+        try:
+            child_output = os.fdopen(child_rfd, "rb").read()
+            # Now, since the file object has no reference anymore, the
+            # standard IO stream behind it will be closed, causing the
+            # end of the the pipe we used to read dialog's output on its
+            # stderr to be closed (this is important, otherwise invoking
+            # dialog enough times will eventually exhaust the maximum number
+            # of open file descriptors).
+        except IOError, v:
+            raise PythonDialogIOError(v)
+
+        return (exit_code, child_output)
+
+    def _perform(self, cmdargs, **kwargs):
+	"""Perform a complete dialog-like program invocation.
+
+        This function invokes the dialog-like program, waits for its
+        termination and returns its exit status and whatever it wrote
+        on its standard error stream.
+
+        Notable exceptions:
+
+            any exception raised by self._call_program() or
+            self._wait_for_program_termination()
+
+        """
+        (child_pid, child_rfd) = \
+                    self._call_program(False, *(cmdargs,), **kwargs)
+        (exit_code, output) = \
+                    self._wait_for_program_termination(child_pid,
+                                                        child_rfd)
+	return (exit_code, output)
+
+    def _strip_xdialog_newline(self, output):
+        """Remove trailing newline (if any), if using Xdialog"""
+        if self.compat == "Xdialog" and output.endswith("\n"):
+            output = output[:-1]
+        return output
+
+    # This is for compatibility with the old dialog.py
+    def _perform_no_options(self, cmd):
+	"""Call dialog without passing any more options."""
+	return os.system(self._dialog_prg + ' ' + cmd)
+
+    # For compatibility with the old dialog.py
+    def clear(self):
+	"""Clear the screen. Equivalent to the dialog --clear option.
+
+        This method is obsolete. Please remove calls to it from your
+        programs.
+
+	"""
+	self._perform_no_options('--clear')
+
+    def calendar(self, text, height=6, width=0, day=0, month=0, year=0,
+                 **kwargs):
+        """Display a calendar dialog box.
+
+        text   -- text to display in the box
+        height -- height of the box (minus the calendar height)
+        width  -- width of the box
+        day    -- inititial day highlighted
+        month  -- inititial month displayed
+        year   -- inititial year selected (0 causes the current date
+                  to be used as the initial date)
+        
+        A calendar box displays month, day and year in separately
+        adjustable windows. If the values for day, month or year are
+        missing or negative, the current date's corresponding values
+        are used. You can increment or decrement any of those using
+        the left, up, right and down arrows. Use tab or backtab to
+        move between windows. If the year is given as zero, the
+        current date is used as an initial value.
+
+        Return a tuple of the form (code, date) where `code' is the
+        exit status (an integer) of the dialog-like program and
+        `date' is a list of the form [day, month, year] (where `day',
+        `month' and `year' are integers corresponding to the date
+        chosen by the user) if the box was closed with OK, or None if
+        it was closed with the Cancel button.
+
+        Notable exceptions:
+            - any exception raised by self._perform()
+            - UnexpectedDialogOutput
+            - PythonDialogReModuleError
+
+	"""
+	(code, output) = self._perform(
+            *(["--calendar", text, str(height), str(width), str(day),
+               str(month), str(year)],),
+            **kwargs)
+        if code == self.DIALOG_OK:
+            try:
+                mo = _calendar_date_rec.match(output)
+            except re.error, v:
+                raise PythonDialogReModuleError(v)
+            
+            if mo is None:
+                raise UnexpectedDialogOutput(
+                    "the dialog-like program returned the following "
+                    "unexpected date with the calendar box: %s" % output)
+            date = map(int, mo.group("day", "month", "year"))
+        else:
+            date = None
+        return (code, date)
+
+    def checklist(self, text, height=15, width=54, list_height=7,
+                  choices=[], **kwargs):
+	"""Display a checklist box.
+
+        text        -- text to display in the box
+        height      -- height of the box
+        width       -- width of the box
+        list_height -- number of entries displayed in the box (which
+                       can be scrolled) at a given time
+        choices     -- a list of tuples (tag, item, status) where
+                       `status' specifies the initial on/off state of
+                       each entry; can be 0 or 1 (integers, 1 meaning
+                       checked, i.e. "on"), or "on", "off" or any
+                       uppercase variant of these two strings.
+
+        Return a tuple of the form (code, [tag, ...]) with the tags
+        for the entries that were selected by the user. `code' is the
+        exit status of the dialog-like program.
+
+        If the user exits with ESC or CANCEL, the returned tag list
+        is empty.
+
+        Notable exceptions:
+
+            any exception raised by self._perform() or _to_onoff()
+
+        """
+        cmd = ["--checklist", text, str(height), str(width), str(list_height)]
+        for t in choices:
+            cmd.extend(((t[0], t[1], _to_onoff(t[2]))))
+
+        # The dialog output cannot be parsed reliably (at least in dialog
+        # 0.9b-20040301) without --separate-output (because double quotes in
+        # tags are escaped with backslashes, but backslashes are not
+        # themselves escaped and you have a problem when a tag ends with a
+        # backslash--the output makes you think you've encountered an embedded
+        # double-quote).
+        kwargs["separate_output"] = True
+
+	(code, output) = self._perform(*(cmd,), **kwargs)
+
+        # Since we used --separate-output, the tags are separated by a newline
+        # in the output. There is also a final newline after the last tag.
+        if output:
+            return (code, string.split(output, '\n')[:-1])
+        else:                           # empty selection
+            return (code, [])
+
+    def fselect(self, filepath, height, width, **kwargs):
+        """Display a file selection dialog box.
+
+        filepath -- initial file path
+        height   -- height of the box
+        width    -- width of the box
+        
+        The file-selection dialog displays a text-entry window in
+        which you can type a filename (or directory), and above that
+        two windows with directory names and filenames.
+
+        Here, filepath can be a file path in which case the file and
+        directory windows will display the contents of the path and
+        the text-entry window will contain the preselected filename.
+
+        Use tab or arrow keys to move between the windows. Within the
+        directory or filename windows, use the up/down arrow keys to
+        scroll the current selection. Use the space-bar to copy the
+        current selection into the text-entry window.
+
+        Typing any printable character switches focus to the
+        text-entry window, entering that character as well as
+        scrolling the directory and filename windows to the closest
+        match.
+
+        Use a carriage return or the "OK" button to accept the
+        current value in the text-entry window, or the "Cancel"
+        button to cancel.
+
+        Return a tuple of the form (code, path) where `code' is the
+        exit status (an integer) of the dialog-like program and
+        `path' is the path chosen by the user (whose last element may
+        be a directory or a file).
+              
+        Notable exceptions:
+
+            any exception raised by self._perform()
+
+	"""
+        (code, output) = self._perform(
+            *(["--fselect", filepath, str(height), str(width)],),
+            **kwargs)
+
+        output = self._strip_xdialog_newline(output)
+        
+	return (code, output)
+    
+    def gauge_start(self, text="", height=8, width=54, percent=0, **kwargs):
+	"""Display gauge box.
+
+        text    -- text to display in the box
+        height  -- height of the box
+        width   -- width of the box
+        percent -- initial percentage shown in the meter
+
+        A gauge box displays a meter along the bottom of the box. The
+        meter indicates a percentage.
+
+        This function starts the dialog-like program telling it to
+        display a gauge box with a text in it and an initial
+        percentage in the meter.
+
+        Return value: undefined.
+
+
+        Gauge typical usage
+        -------------------
+
+        Gauge typical usage (assuming that `d' is an instance of the
+	Dialog class) looks like this:
+	    d.gauge_start()
+	    # do something
+	    d.gauge_update(10)       # 10% of the whole task is done
+	    # ...
+	    d.gauge_update(100, "any text here") # work is done
+	    exit_code = d.gauge_stop()           # cleanup actions
+
+
+        Notable exceptions:
+            - any exception raised by self._call_program()
+            - PythonDialogOSError
+
+	"""
+        (child_pid, child_rfd, child_stdin_wfd) = self._call_program(
+            True,
+            *(["--gauge", text, str(height), str(width), str(percent)],),
+            **kwargs)
+        try:
+            self._gauge_process = {
+                "pid": child_pid,
+                "stdin": os.fdopen(child_stdin_wfd, "wb"),
+                "child_rfd": child_rfd
+                }
+        except os.error, v:
+            raise PythonDialogOSError(v.strerror)
+            
+    def gauge_update(self, percent, text="", update_text=0):
+	"""Update a running gauge box.
+	
+        percent     -- new percentage to show in the gauge meter
+        text        -- new text to optionally display in the box
+        update-text -- boolean indicating whether to update the
+                       text in the box
+
+        This function updates the percentage shown by the meter of a
+        running gauge box (meaning `gauge_start' must have been
+        called previously). If update_text is true (for instance, 1),
+        the text displayed in the box is also updated.
+
+	See the `gauge_start' function's documentation for
+	information about how to use a gauge.
+
+        Return value: undefined.
+
+        Notable exception: PythonDialogIOError can be raised if there
+                           is an I/O error while writing to the pipe
+                           used to talk to the dialog-like program.
+
+	"""
+	if update_text:
+	    gauge_data = "%d\nXXX\n%s\nXXX\n" % (percent, text)
+	else:
+	    gauge_data = "%d\n" % percent
+	try:
+            self._gauge_process["stdin"].write(gauge_data)
+            self._gauge_process["stdin"].flush()
+        except IOError, v:
+            raise PythonDialogIOError(v)
+    
+    # For "compatibility" with the old dialog.py...
+    gauge_iterate = gauge_update
+
+    def gauge_stop(self):
+	"""Terminate a running gauge.
+
+        This function performs the appropriate cleanup actions to
+        terminate a running gauge (started with `gauge_start').
+	
+	See the `gauge_start' function's documentation for
+	information about how to use a gauge.
+
+        Return value: undefined.
+
+        Notable exceptions:
+            - any exception raised by
+              self._wait_for_program_termination()
+            - PythonDialogIOError can be raised if closing the pipe
+              used to talk to the dialog-like program fails.
+
+	"""
+        p = self._gauge_process
+        # Close the pipe that we are using to feed dialog's stdin
+        try:
+            p["stdin"].close()
+        except IOError, v:
+            raise PythonDialogIOError(v)
+        exit_code = \
+                  self._wait_for_program_termination(p["pid"],
+                                                      p["child_rfd"])[0]
+        return exit_code
+
+    def infobox(self, text, height=10, width=30, **kwargs):
+        """Display an information dialog box.
+
+        text   -- text to display in the box
+        height -- height of the box
+        width  -- width of the box
+
+        An info box is basically a message box. However, in this
+        case, dialog will exit immediately after displaying the
+        message to the user. The screen is not cleared when dialog
+        exits, so that the message will remain on the screen until
+        the calling shell script clears it later. This is useful
+        when you want to inform the user that some operations are
+        carrying on that may require some time to finish.
+
+        Return the exit status (an integer) of the dialog-like
+        program.
+
+        Notable exceptions:
+
+            any exception raised by self._perform()
+
+	"""
+	return self._perform(
+            *(["--infobox", text, str(height), str(width)],),
+            **kwargs)[0]
+
+    def inputbox(self, text, height=10, width=30, init='', **kwargs):
+        """Display an input dialog box.
+
+        text   -- text to display in the box
+        height -- height of the box
+        width  -- width of the box
+        init   -- default input string
+
+        An input box is useful when you want to ask questions that
+        require the user to input a string as the answer. If init is
+        supplied it is used to initialize the input string. When
+        entering the string, the BACKSPACE key can be used to
+        correct typing errors. If the input string is longer than
+        can fit in the dialog box, the input field will be scrolled.
+
+        Return a tuple of the form (code, string) where `code' is the
+        exit status of the dialog-like program and `string' is the
+        string entered by the user.
+
+        Notable exceptions:
+
+            any exception raised by self._perform()
+
+	"""
+        (code, tag) = self._perform(
+            *(["--inputbox", text, str(height), str(width), init],),
+            **kwargs)
+
+        tag = self._strip_xdialog_newline(tag)
+        
+	return (code, tag)
+
+    def menu(self, text, height=15, width=54, menu_height=7, choices=[],
+             **kwargs):
+        """Display a menu dialog box.
+
+        text        -- text to display in the box
+        height      -- height of the box
+        width       -- width of the box
+        menu_height -- number of entries displayed in the box (which
+                       can be scrolled) at a given time
+        choices     -- a sequence of (tag, item) or (tag, item, help)
+                       tuples (the meaning of each `tag', `item' and
+                       `help' is explained below)
+
+
+        Overview
+        --------
+
+        As its name suggests, a menu box is a dialog box that can be
+        used to present a list of choices in the form of a menu for
+        the user to choose. Choices are displayed in the order given.
+
+        Each menu entry consists of a `tag' string and an `item'
+        string. The tag gives the entry a name to distinguish it from
+        the other entries in the menu. The item is a short
+        description of the option that the entry represents.
+
+        The user can move between the menu entries by pressing the
+        UP/DOWN keys, the first letter of the tag as a hot-key, or
+        the number keys 1-9. There are menu-height entries displayed
+        in the menu at one time, but the menu will be scrolled if
+        there are more entries than that.
+
+
+        Providing on-line help facilities
+        ---------------------------------
+
+        If this function is called with item_help=1 (keyword
+        argument), the option --item-help is passed to dialog and the
+        tuples contained in `choices' must contain 3 elements each :
+        (tag, item, help). The help string for the highlighted item
+        is displayed in the bottom line of the screen and updated as
+        the user highlights other items.
+
+        If item_help=0 or if this keyword argument is not passed to
+        this function, the tuples contained in `choices' must contain
+        2 elements each : (tag, item).
+
+        If this function is called with help_button=1, it must also
+        be called with item_help=1 (this is a limitation of dialog),
+        therefore the tuples contained in `choices' must contain 3
+        elements each as explained in the previous paragraphs. This
+        will cause a Help button to be added to the right of the
+        Cancel button (by passing --help-button to dialog).
+
+
+        Return value
+        ------------
+
+        Return a tuple of the form (exit_info, string).
+
+        `exit_info' is either:
+          - an integer, being the the exit status of the dialog-like
+            program
+          - or the string "help", meaning that help_button=1 was
+            passed and that the user chose the Help button instead of
+            OK or Cancel.
+
+        The meaning of `string' depends on the value of exit_info:
+          - if `exit_info' is 0, `string' is the tag chosen by the
+            user
+          - if `exit_info' is "help", `string' is the `help' string
+            from the `choices' argument corresponding to the item
+            that was highlighted when the user chose the Help button
+          - otherwise (the user chose Cancel or pressed Esc, or there
+            was a dialog error), the value of `string' is undefined.
+
+        Notable exceptions:
+
+            any exception raised by self._perform()
+
+	"""
+        cmd = ["--menu", text, str(height), str(width), str(menu_height)]
+        for t in choices:
+            cmd.extend(t)
+	(code, output) = self._perform(*(cmd,), **kwargs)
+
+        output = self._strip_xdialog_newline(output)
+        
+        if "help_button" in kwargs.keys() and output.startswith("HELP "):
+            return ("help", output[5:])
+        else:
+            return (code, output)
+
+    def msgbox(self, text, height=10, width=30, **kwargs):
+        """Display a message dialog box.
+
+        text   -- text to display in the box
+        height -- height of the box
+        width  -- width of the box
+
+        A message box is very similar to a yes/no box. The only
+        difference between a message box and a yes/no box is that a
+        message box has only a single OK button. You can use this
+        dialog box to display any message you like. After reading
+        the message, the user can press the ENTER key so that dialog
+        will exit and the calling program can continue its
+        operation.
+
+        Return the exit status (an integer) of the dialog-like
+        program.
+
+        Notable exceptions:
+
+            any exception raised by self._perform()
+
+	"""
+	return self._perform(
+            *(["--msgbox", text, str(height), str(width)],),
+            **kwargs)[0]
+
+    def passwordbox(self, text, height=10, width=60, init='', **kwargs):
+        """Display an password input dialog box.
+
+        text   -- text to display in the box
+        height -- height of the box
+        width  -- width of the box
+        init   -- default input password
+
+        A password box is similar to an input box, except that the
+        text the user enters is not displayed. This is useful when
+        prompting for passwords or other sensitive information. Be
+        aware that if anything is passed in "init", it will be
+        visible in the system's process table to casual snoopers.
+        Also, it is very confusing to the user to provide them with a
+        default password they cannot see. For these reasons, using
+        "init" is highly discouraged.
+
+        Return a tuple of the form (code, password) where `code' is
+        the exit status of the dialog-like program and `password' is
+        the password entered by the user.
+
+        Notable exceptions:
+
+            any exception raised by self._perform()
+
+	"""
+	(code, password) = self._perform(
+            *(["--passwordbox", text, str(height), str(width), init],),
+            **kwargs)
+
+        password = self._strip_xdialog_newline(password)
+
+        return (code, password)
+
+    def radiolist(self, text, height=15, width=54, list_height=7,
+                  choices=[], **kwargs):
+	"""Display a radiolist box.
+
+        text        -- text to display in the box
+        height      -- height of the box
+        width       -- width of the box
+        list_height -- number of entries displayed in the box (which
+                       can be scrolled) at a given time
+        choices     -- a list of tuples (tag, item, status) where
+                       `status' specifies the initial on/off state
+                       each entry; can be 0 or 1 (integers, 1 meaning
+                       checked, i.e. "on"), or "on", "off" or any
+                       uppercase variant of these two strings.
+                       No more than one entry should  be set to on.
+
+        A radiolist box is similar to a menu box. The main difference
+        is that you can indicate which entry is initially selected,
+        by setting its status to on.
+
+        Return a tuple of the form (code, tag) with the tag for the
+        entry that was chosen by the user. `code' is the exit status
+        of the dialog-like program.
+
+        If the user exits with ESC or CANCEL, or if all entries were
+        initially set to off and not altered before the user chose
+        OK, the returned tag is the empty string.
+
+        Notable exceptions:
+
+            any exception raised by self._perform() or _to_onoff()
+
+	"""
+        cmd = ["--radiolist", text, str(height), str(width), str(list_height)]
+        for t in choices:
+            cmd.extend(((t[0], t[1], _to_onoff(t[2]))))
+
+        (code, tag) = self._perform(*(cmd,), **kwargs)
+
+        tag = self._strip_xdialog_newline(tag)
+            
+	return (code, tag)
+
+    def scrollbox(self, text, height=20, width=78, **kwargs):
+	"""Display a string in a scrollable box.
+
+        text   -- text to display in the box
+        height -- height of the box
+        width  -- width of the box
+
+        This method is a layer on top of textbox. The textbox option
+        in dialog allows to display file contents only. This method
+        allows you to display any text in a scrollable box. This is
+        simply done by creating a temporary file, calling textbox and
+        deleting the temporary file afterwards.
+
+        Return the dialog-like program's exit status.
+
+        Notable exceptions:
+            - UnableToCreateTemporaryDirectory
+            - PythonDialogIOError
+            - PythonDialogOSError
+            - exceptions raised by the tempfile module (which are
+              unfortunately not mentioned in its documentation, at
+              least in Python 2.3.3...)
+
+	"""
+        # In Python < 2.3, the standard library does not have
+        # tempfile.mkstemp(), and unfortunately, tempfile.mktemp() is
+        # insecure. So, I create a non-world-writable temporary directory and
+        # store the temporary file in this directory.
+        try:
+            # We want to ensure that f is already bound in the local
+            # scope when the finally clause (see below) is executed
+            f = 0
+            tmp_dir = _create_temporary_directory()
+            # If we are here, tmp_dir *is* created (no exception was raised),
+            # so chances are great that os.rmdir(tmp_dir) will succeed (as
+            # long as tmp_dir is empty).
+            #
+            # Don't move the _create_temporary_directory() call inside the
+            # following try statement, otherwise the user will always see a
+            # PythonDialogOSError instead of an
+            # UnableToCreateTemporaryDirectory because whenever
+            # UnableToCreateTemporaryDirectory is raised, the subsequent
+            # os.rmdir(tmp_dir) is bound to fail.
+            try:
+                fName = os.path.join(tmp_dir, "text")
+                # No race condition as with the deprecated tempfile.mktemp()
+                # since tmp_dir is not world-writable.
+                f = open(fName, "wb")
+                f.write(text)
+                f.close()
+
+                # Ask for an empty title unless otherwise specified
+                if not "title" in kwargs.keys():
+                    kwargs["title"] = ""
+
+                return self._perform(
+                    *(["--textbox", fName, str(height), str(width)],),
+                    **kwargs)[0]
+            finally:
+                if type(f) == types.FileType:
+                    f.close()           # Safe, even several times
+                    os.unlink(fName)
+                os.rmdir(tmp_dir)
+        except os.error, v:
+            raise PythonDialogOSError(v.strerror)
+        except IOError, v:
+            raise PythonDialogIOError(v)
+
+    def tailbox(self, filename, height=20, width=60, **kwargs):
+        """Display the contents of a file in a dialog box, as in "tail -f".
+
+        filename -- name of the file whose contents is to be
+                    displayed in the box
+        height   -- height of the box
+        width    -- width of the box
+
+        Display the contents of the specified file, updating the
+        dialog box whenever the file grows, as with the "tail -f"
+        command.
+
+        Return the exit status (an integer) of the dialog-like
+        program.
+
+        Notable exceptions:
+
+            any exception raised by self._perform()
+
+	"""
+	return self._perform(
+            *(["--tailbox", filename, str(height), str(width)],),
+            **kwargs)[0]
+    # No tailboxbg widget, at least for now.
+
+    def textbox(self, filename, height=20, width=60, **kwargs):
+        """Display the contents of a file in a dialog box.
+
+        filename -- name of the file whose contents is to be
+                    displayed in the box
+        height   -- height of the box
+        width    -- width of the box
+
+        A text box lets you display the contents of a text file in a
+        dialog box. It is like a simple text file viewer. The user
+        can move through the file by using the UP/DOWN, PGUP/PGDN
+        and HOME/END keys available on most keyboards. If the lines
+        are too long to be displayed in the box, the LEFT/RIGHT keys
+        can be used to scroll the text region horizontally. For more
+        convenience, forward and backward searching functions are
+        also provided.
+
+        Return the exit status (an integer) of the dialog-like
+        program.
+
+        Notable exceptions:
+
+            any exception raised by self._perform()
+
+	"""
+        # This is for backward compatibility... not that it is
+        # stupid, but I prefer explicit programming.
+        if not "title" in kwargs.keys():
+	    kwargs["title"] = filename
+	return self._perform(
+            *(["--textbox", filename, str(height), str(width)],),
+            **kwargs)[0]
+
+    def timebox(self, text, height=3, width=30, hour=-1, minute=-1,
+                second=-1, **kwargs):
+        """Display a time dialog box.
+
+        text   -- text to display in the box
+        height -- height of the box
+        width  -- width of the box
+        hour   -- inititial hour selected
+        minute -- inititial minute selected
+        second -- inititial second selected
+        
+        A dialog is displayed which allows you to select hour, minute
+        and second. If the values for hour, minute or second are
+        negative (or not explicitely provided, as they default to
+        -1), the current time's corresponding values are used. You
+        can increment or decrement any of those using the left-, up-,
+        right- and down-arrows. Use tab or backtab to move between
+        windows.
+
+        Return a tuple of the form (code, time) where `code' is the
+        exit status (an integer) of the dialog-like program and
+        `time' is a list of the form [hour, minute, second] (where
+        `hour', `minute' and `second' are integers corresponding to
+        the time chosen by the user) if the box was closed with OK,
+        or None if it was closed with the Cancel button.
+
+        Notable exceptions:
+            - any exception raised by self._perform()
+            - PythonDialogReModuleError
+            - UnexpectedDialogOutput
+
+	"""
+	(code, output) = self._perform(
+            *(["--timebox", text, str(height), str(width),
+               str(hour), str(minute), str(second)],),
+            **kwargs)
+        if code == self.DIALOG_OK:
+            try:
+                mo = _timebox_time_rec.match(output)
+                if mo is None:
+                    raise UnexpectedDialogOutput(
+                        "the dialog-like program returned the following "
+                        "unexpected time with the --timebox option: %s" % output)
+                time = map(int, mo.group("hour", "minute", "second"))
+            except re.error, v:
+                raise PythonDialogReModuleError(v)
+        else:
+            time = None
+        return (code, time)
+
+    def yesno(self, text, height=10, width=30, **kwargs):
+        """Display a yes/no dialog box.
+
+        text   -- text to display in the box
+        height -- height of the box
+        width  -- width of the box
+
+        A yes/no dialog box of size `height' rows by `width' columns
+        will be displayed. The string specified by `text' is
+        displayed inside the dialog box. If this string is too long
+        to fit in one line, it will be automatically divided into
+        multiple lines at appropriate places. The text string can
+        also contain the sub-string "\\n" or newline characters to
+        control line breaking explicitly. This dialog box is useful
+        for asking questions that require the user to answer either
+        yes or no. The dialog box has a Yes button and a No button,
+        in which the user can switch between by pressing the TAB
+        key.
+
+        Return the exit status (an integer) of the dialog-like
+        program.
+
+        Notable exceptions:
+
+            any exception raised by self._perform()
+
+	"""
+	return self._perform(
+            *(["--yesno", text, str(height), str(width)],),
+            **kwargs)[0]
