? 404.php
Index: .htaccess
===================================================================
RCS file: /cvs/drupal/drupal/.htaccess,v
retrieving revision 1.58
diff -u -3 -p -r1.58 .htaccess
--- .htaccess	9 Oct 2004 20:41:49 -0000	1.58
+++ .htaccess	5 Jan 2005 10:40:55 -0000
@@ -12,8 +12,12 @@
 Options -Indexes
 Options +FollowSymLinks
 
-# Customized server error messages:
-ErrorDocument 404 /index.php
+# Customized server error messages and/or GET-only clean URLs.
+# If you do not have mod_rewrite support on your server, setting the 
+# ErrorDocument to 404.php can allow clean URLs for GET,
+# but not for POST (i.e. form submission) requests. For this to work,
+# you need to enable GET-only clean URLs on the setup screen.
+ErrorDocument 404 404.php
 
 # Set the default handler to index.php:
 DirectoryIndex index.php
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.415
diff -u -3 -p -r1.415 common.inc
--- includes/common.inc	30 Dec 2004 13:13:22 -0000	1.415
+++ includes/common.inc	5 Jan 2005 10:41:00 -0000
@@ -916,6 +916,25 @@ function format_name($object) {
  * must be explicitly generated by modules.
  */
 
+ /**
+ * Reverse of parse_str().  Converts array into
+ * string with query format. 
+ *
+ * By dante@lorenso.com, from PHP documentation. Might need to be moved away 
+ * from here.
+ */
+
+function query_str($params) {
+  if (count($params) == 0) return NULL;
+
+  $str = '';
+  foreach ($params as $key => $value) {
+    $str .= (strlen($str) < 1) ? '' : '&';
+    $str .= $key . '=' . rawurlencode($value);
+  }
+  return ($str);
+}
+
 /**
  * Generate a form from a set of form elements.
  *
@@ -931,9 +950,43 @@ function format_name($object) {
  *   An HTML string with the contents of $form wrapped in a form tag.
  */
 function form($form, $method = 'post', $action = NULL, $attributes = NULL) {
+  global $base_url;
   if (!$action) {
     $action = request_uri();
   }
+
+  $parsed_base_url = parse_url($base_url);
+  $base_path = $parsed_base_url['path'];
+  $parsed_action = parse_url($action);
+  $action_query = isset($parsed_action['query']) ? $parsed_action['query'] : NULL;
+  $action_path = isset($parsed_action['path']) ? $parsed_action['path'] : NULL;
+  $action_fragment = isset($parsed_action['fragment']) ? $parsed_action['fragment'] : NULL;
+  
+  if (substr($action_path, 0, strlen($base_path)) == $base_path) {
+    parse_str($action_query, $query_components);
+
+    $remainder = substr($action_path,strlen($base_path));
+
+    // Chop a leading slash, if any.
+    if (substr($remainder, 0, 1) == "/") {
+      $remainder = substr($remainder, 1);
+    }
+
+    if (isset($query_components['q']))
+    {
+      // Query of style index.php?q=...
+      $q_string = $query_components['q'];
+      unset($query_components['q']);
+      
+      $action = url($q_string, query_str($query_components), $action_fragment, FALSE, TRUE);
+    }
+    else
+    {
+      // Query of "clean" style.
+      $action = url($remainder, $action_query, $action_fragment, FALSE, TRUE);
+    }
+  }
+
   return '<form action="'. $action .'" method="'. $method .'"'. drupal_attributes($attributes) .">\n". $form ."\n</form>\n";
 }
 
@@ -1395,33 +1448,47 @@ function form_weight($title = NULL, $nam
  * @param $absolute
  *   Whether to force the output to be an absolute link (beginning with http:).
  *   Useful for links that will be displayed outside the site, such as in an RSS feed.
+ * @param $isform
+ *   Whether the URL is meant for form submission. This may suppress the generation
+ *   of clean URLs in "Clean only for GET" mode.
  * @return
  *   an HTML string containing a link to the given path.
  *
  * When creating links in modules, consider whether l() could be a better
  * alternative than url().
  */
-function url($path = NULL, $query = NULL, $fragment = NULL, $absolute = FALSE) {
+function url($path = NULL, $query = NULL, $fragment = NULL, $absolute = FALSE, $isform = FALSE) {
   global $base_url;
 
   static $script;
 
-  if (empty($script)) {
-    // On some web servers, such as IIS, we can't omit "index.php".  So, we
-    // generate "index.php?q=foo" instead of "?q=foo" on anything that is not
-    // Apache.
-    $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === false) ? 'index.php' : '';
-  }
-
   $path = drupal_get_path_alias($path);
 
   if (isset($fragment)) {
     $fragment = '#'. $fragment;
   }
 
+  $clean_url_var = variable_get('clean_url', '0');
+  $use_clean_url = $clean_url_var != '0';
+  
+  if ($isform && $use_clean_url == "2") {
+    $use_clean_url = FALSE;
+
+    // We need to force absolute since we don't want /admin/index.php?q=...
+    // put together by the browser if all we specify is index.php?q=... .
+    $absolute = TRUE;
+  }
+
   $base = ($absolute ? $base_url . '/' : '');
 
-  if (variable_get('clean_url', '0') == '0') {
+  if (empty($script)) {
+    // On some web servers, such as IIS, we can't omit "index.php".  So, we
+    // generate "index.php?q=foo" instead of "?q=foo" on anything that is not
+    // Apache.
+    $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === false) ? 'index.php' : '';
+  }
+
+  if (!$use_clean_url) {
     if (isset($path)) {
       if (isset($query)) {
         return $base . $script .'?q='. $path .'&amp;'. $query . $fragment;
Index: modules/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system.module,v
retrieving revision 1.190
diff -u -3 -p -r1.190 system.module
--- modules/system.module	11 Dec 2004 14:13:24 -0000	1.190
+++ modules/system.module	5 Jan 2005 10:41:03 -0000
@@ -194,7 +194,7 @@ function system_view_general() {
   // check if clean URLs are supported (HTTP 200 = Ok)
   $request = drupal_http_request($GLOBALS['base_url'] . '/system/test');
   $supported = $request->code == 200;
-  $group .= form_radios(t('Clean URLs'), 'clean_url', variable_get('clean_url', 0), array(t('Disabled'), t('Enabled')), t('This option makes Drupal emit clean URLs (i.e. without <code>?q=</code> in the URL). You\'ll need <code>ModRewrite</code> support for this to work. See the <code>.htaccess</code> file in Drupal\'s top-level directory for more information.'), false, $supported ? NULL : array('disabled' => 'disabled'));
+  $group .= form_radios(t('Clean URLs'), 'clean_url', variable_get('clean_url', 0), array(t('Disabled'), t('Enabled'), t('Enabled for GET requests only')), t('This option makes Drupal emit clean URLs (i.e. without <code>?q=</code> in the URL). You will need <code>ModRewrite</code> or <code>ErrorDocument</code> support for this to work. See the <code>.htaccess</code> file in Drupal\'s top-level directory for more information.'), false, $supported ? NULL : array('disabled' => 'disabled'));
 
   $output = form_group(t('General settings'), $group);
 
