Back to index

lightning-sunbird  0.9+nobinonly
nsFormSubmission.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsIFormSubmission.h"
00040 
00041 #include "nsPresContext.h"
00042 #include "nsCOMPtr.h"
00043 #include "nsIForm.h"
00044 #include "nsILinkHandler.h"
00045 #include "nsIDocument.h"
00046 #include "nsHTMLAtoms.h"
00047 #include "nsIHTMLDocument.h"
00048 #include "nsIFormControl.h"
00049 #include "nsIScriptGlobalObject.h"
00050 #include "nsIDOMHTMLFormElement.h"
00051 #include "nsDOMError.h"
00052 #include "nsGenericHTMLElement.h"
00053 #include "nsISaveAsCharset.h"
00054 
00055 // JBK added for submit move from content frame
00056 #include "nsIFile.h"
00057 #include "nsDirectoryServiceDefs.h"
00058 #include "nsIFormProcessor.h"
00059 #include "nsIURI.h"
00060 #include "nsNetUtil.h"
00061 #include "nsLinebreakConverter.h"
00062 #include "nsICharsetConverterManager.h"
00063 #include "nsICharsetAlias.h"
00064 #include "nsEscape.h"
00065 #include "nsUnicharUtils.h"
00066 #include "nsIMultiplexInputStream.h"
00067 #include "nsIMIMEInputStream.h"
00068 #include "nsIConsoleService.h"
00069 #include "nsIScriptError.h"
00070 #include "nsIStringBundle.h"
00071 
00072 //BIDI
00073 #include "nsBidiUtils.h"
00074 //end
00075 
00076 static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
00077 static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID);
00078 
00083 class nsFormSubmission : public nsIFormSubmission {
00084 
00085 public:
00086 
00094   nsFormSubmission(const nsACString& aCharset,
00095                    nsISaveAsCharset* aEncoder,
00096                    nsIFormProcessor* aFormProcessor,
00097                    PRInt32 aBidiOptions)
00098     : mCharset(aCharset),
00099       mEncoder(aEncoder),
00100       mFormProcessor(aFormProcessor),
00101       mBidiOptions(aBidiOptions)
00102   {
00103   };
00104   virtual ~nsFormSubmission()
00105   {
00106   };
00107 
00108   NS_DECL_ISUPPORTS
00109 
00110   //
00111   // nsIFormSubmission
00112   //
00113   virtual nsresult SubmitTo(nsIURI* aActionURI, const nsAString& aTarget,
00114                             nsIContent* aSource, nsPresContext* aPresContext,
00115                             nsIDocShell** aDocShell, nsIRequest** aRequest);
00116 
00121   NS_IMETHOD Init() = 0;
00122 
00123 protected:
00124   // this is essentially the nsFormSubmission interface (to be overridden)
00132   NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
00133                                   nsIInputStream** aPostDataStream) = 0;
00134 
00135   // Helpers
00145   nsresult ProcessValue(nsIDOMHTMLElement* aSource, const nsAString& aName, 
00146                         const nsAString& aValue, nsAString& aResult);
00147 
00148   // Encoding Helpers
00156   nsresult EncodeVal(const nsAString& aStr, nsACString& aResult);
00164   nsresult UnicodeToNewBytes(const nsAString& aStr, nsISaveAsCharset* aEncoder,
00165                              nsACString& aOut);
00166 
00168   nsCString mCharset;
00172   nsCOMPtr<nsISaveAsCharset> mEncoder;
00174   nsCOMPtr<nsIFormProcessor> mFormProcessor;
00176   PRInt32 mBidiOptions;
00177 
00178 public:
00179   // Static helpers
00180 
00188   static void GetSubmitCharset(nsGenericHTMLElement* aForm,
00189                                PRUint8 aCtrlsModAtSubmit,
00190                                nsACString& aCharset);
00198   static nsresult GetEncoder(nsGenericHTMLElement* aForm,
00199                              nsPresContext* aPresContext,
00200                              const nsACString& aCharset,
00201                              nsISaveAsCharset** aEncoder);
00210   static void GetEnumAttr(nsGenericHTMLElement* aForm,
00211                           nsIAtom* aAtom, PRInt32* aValue);
00212 };
00213 
00214 //
00215 // Static helper methods that don't really have nothing to do with nsFormSub
00216 //
00217 
00224 static nsresult
00225 SendJSWarning(nsIContent* aContent,
00226               const char* aWarningName);
00234 static nsresult
00235 SendJSWarning(nsIContent* aContent,
00236               const char* aWarningName,
00237               const nsAFlatString& aWarningArg1);
00246 static nsresult
00247 SendJSWarning(nsIContent* aContent,
00248               const char* aWarningName,
00249               const PRUnichar** aWarningArgs, PRUint32 aWarningArgsLen);
00250 
00251 
00252 class nsFSURLEncoded : public nsFormSubmission
00253 {
00254 public:
00264   nsFSURLEncoded(const nsACString& aCharset,
00265                  nsISaveAsCharset* aEncoder,
00266                  nsIFormProcessor* aFormProcessor,
00267                  PRInt32 aBidiOptions,
00268                  PRInt32 aMethod)
00269     : nsFormSubmission(aCharset, aEncoder, aFormProcessor, aBidiOptions),
00270       mMethod(aMethod)
00271   {
00272   }
00273   virtual ~nsFSURLEncoded()
00274   {
00275   }
00276 
00277   NS_DECL_ISUPPORTS_INHERITED
00278 
00279   // nsIFormSubmission
00280   virtual nsresult AddNameValuePair(nsIDOMHTMLElement* aSource,
00281                                     const nsAString& aName,
00282                                     const nsAString& aValue);
00283   virtual nsresult AddNameFilePair(nsIDOMHTMLElement* aSource,
00284                                    const nsAString& aName,
00285                                    const nsAString& aFilename,
00286                                    nsIInputStream* aStream,
00287                                    const nsACString& aContentType,
00288                                    PRBool aMoreFilesToCome);
00289   virtual PRBool AcceptsFiles() const
00290   {
00291     return PR_FALSE;
00292   }
00293 
00294   NS_IMETHOD Init();
00295 
00296 protected:
00297   // nsFormSubmission
00298   NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
00299                                   nsIInputStream** aPostDataStream);
00300 
00301   // Helpers
00310   nsresult URLEncode(const nsAString& aStr, nsCString& aEncoded);
00311 
00312 private:
00317   PRInt32 mMethod;
00318 
00320   nsCString mQueryString;
00321 
00323   PRBool mWarnedFileControl;
00324 };
00325 
00326 NS_IMPL_RELEASE_INHERITED(nsFSURLEncoded, nsFormSubmission)
00327 NS_IMPL_ADDREF_INHERITED(nsFSURLEncoded, nsFormSubmission)
00328 NS_IMPL_QUERY_INTERFACE_INHERITED0(nsFSURLEncoded, nsFormSubmission)
00329 
00330 nsresult
00331 nsFSURLEncoded::AddNameValuePair(nsIDOMHTMLElement* aSource,
00332                                  const nsAString& aName,
00333                                  const nsAString& aValue)
00334 {
00335   //
00336   // Check if there is an input type=file so that we can warn
00337   //
00338   if (!mWarnedFileControl) {
00339     nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aSource);
00340     if (formControl->GetType() == NS_FORM_INPUT_FILE) {
00341       nsCOMPtr<nsIContent> content = do_QueryInterface(aSource);
00342       SendJSWarning(content, "ForgotFileEnctypeWarning");
00343       mWarnedFileControl = PR_TRUE;
00344     }
00345   }
00346 
00347   //
00348   // Let external code process (and possibly change) value
00349   //
00350   nsAutoString processedValue;
00351   nsresult rv = ProcessValue(aSource, aName, aValue, processedValue);
00352 
00353   //
00354   // Encode value
00355   //
00356   nsCString convValue;
00357   if (NS_SUCCEEDED(rv)) {
00358     rv = URLEncode(processedValue, convValue);
00359   }
00360   else {
00361     rv = URLEncode(aValue, convValue);
00362   }
00363   NS_ENSURE_SUCCESS(rv, rv);
00364 
00365   //
00366   // Encode name
00367   //
00368   nsCAutoString convName;
00369   rv = URLEncode(aName, convName);
00370   NS_ENSURE_SUCCESS(rv, rv);
00371 
00372 
00373   //
00374   // Append data to string
00375   //
00376   if (mQueryString.IsEmpty()) {
00377     mQueryString += convName + NS_LITERAL_CSTRING("=") + convValue;
00378   } else {
00379     mQueryString += NS_LITERAL_CSTRING("&") + convName
00380                   + NS_LITERAL_CSTRING("=") + convValue;
00381   }
00382 
00383   return NS_OK;
00384 }
00385 
00386 nsresult
00387 nsFSURLEncoded::AddNameFilePair(nsIDOMHTMLElement* aSource,
00388                                 const nsAString& aName,
00389                                 const nsAString& aFilename,
00390                                 nsIInputStream* aStream,
00391                                 const nsACString& aContentType,
00392                                 PRBool aMoreFilesToCome)
00393 {
00394   return AddNameValuePair(aSource, aName, aFilename);
00395 }
00396 
00397 //
00398 // nsFormSubmission
00399 //
00400 NS_IMETHODIMP
00401 nsFSURLEncoded::Init()
00402 {
00403   mQueryString.Truncate();
00404   mWarnedFileControl = PR_FALSE;
00405   return NS_OK;
00406 }
00407 
00408 static void
00409 HandleMailtoSubject(nsCString& aPath) {
00410 
00411   // Walk through the string and see if we have a subject already.
00412   PRBool hasSubject = PR_FALSE;
00413   PRBool hasParams = PR_FALSE;
00414   PRInt32 paramSep = aPath.FindChar('?');
00415   while (paramSep != kNotFound && paramSep < (PRInt32)aPath.Length()) {
00416     hasParams = PR_TRUE;
00417 
00418     // Get the end of the name at the = op.  If it is *after* the next &,
00419     // assume that someone made a parameter without an = in it
00420     PRInt32 nameEnd = aPath.FindChar('=', paramSep+1);
00421     PRInt32 nextParamSep = aPath.FindChar('&', paramSep+1);
00422     if (nextParamSep == kNotFound) {
00423       nextParamSep = aPath.Length();
00424     }
00425 
00426     // If the = op is after the &, this parameter is a name without value.
00427     // If there is no = op, same thing.
00428     if (nameEnd == kNotFound || nextParamSep < nameEnd) {
00429       nameEnd = nextParamSep;
00430     }
00431 
00432     if (nameEnd != kNotFound) {
00433       if (Substring(aPath, paramSep+1, nameEnd-(paramSep+1)) ==
00434           NS_LITERAL_CSTRING("subject")) {
00435         hasSubject = PR_TRUE;
00436         break;
00437       }
00438     }
00439 
00440     paramSep = nextParamSep;
00441   }
00442 
00443   // If there is no subject, append a preformed subject to the mailto line
00444   if (!hasSubject) {
00445     if (hasParams) {
00446       aPath.Append('&');
00447     } else {
00448       aPath.Append('?');
00449     }
00450 
00451     // Get the default subject
00452     nsXPIDLString brandName;
00453     nsresult rv =
00454       nsContentUtils::GetLocalizedString(nsContentUtils::eBRAND_PROPERTIES,
00455                                          "brandShortName", brandName);
00456     if (NS_FAILED(rv))
00457       return;
00458     const PRUnichar *formatStrings[] = { brandName.get() };
00459     nsXPIDLString subjectStr;
00460     rv = nsContentUtils::FormatLocalizedString(
00461                                            nsContentUtils::eFORMS_PROPERTIES,
00462                                            "DefaultFormSubject",
00463                                            formatStrings,
00464                                            NS_ARRAY_LENGTH(formatStrings),
00465                                            subjectStr);
00466     if (NS_FAILED(rv))
00467       return;
00468     aPath.AppendLiteral("subject=");
00469     nsCString subjectStrEscaped;
00470     aPath.Append(NS_EscapeURL(NS_ConvertUTF16toUTF8(subjectStr), esc_Query,
00471                               subjectStrEscaped));
00472   }
00473 }
00474 
00475 NS_IMETHODIMP
00476 nsFSURLEncoded::GetEncodedSubmission(nsIURI* aURI,
00477                                      nsIInputStream** aPostDataStream)
00478 {
00479   nsresult rv = NS_OK;
00480 
00481   *aPostDataStream = nsnull;
00482 
00483   if (mMethod == NS_FORM_METHOD_POST) {
00484 
00485     PRBool isMailto = PR_FALSE;
00486     aURI->SchemeIs("mailto", &isMailto);
00487     if (isMailto) {
00488 
00489       nsCAutoString path;
00490       rv = aURI->GetPath(path);
00491       NS_ENSURE_SUCCESS(rv, rv);
00492 
00493       HandleMailtoSubject(path);
00494 
00495       // Append the body to and force-plain-text args to the mailto line
00496       nsCString escapedBody;
00497       escapedBody.Adopt(nsEscape(mQueryString.get(), url_XAlphas));
00498 
00499       path += NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody;
00500 
00501       rv = aURI->SetPath(path);
00502 
00503     } else {
00504 
00505       nsCOMPtr<nsIInputStream> dataStream;
00506       // XXX We *really* need to either get the string to disown its data (and
00507       // not destroy it), or make a string input stream that owns the CString
00508       // that is passed to it.  Right now this operation does a copy.
00509       rv = NS_NewCStringInputStream(getter_AddRefs(dataStream), mQueryString);
00510       NS_ENSURE_SUCCESS(rv, rv);
00511 
00512       nsCOMPtr<nsIMIMEInputStream> mimeStream(
00513         do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
00514       NS_ENSURE_SUCCESS(rv, rv);
00515 
00516 #ifdef SPECIFY_CHARSET_IN_CONTENT_TYPE
00517       mimeStream->AddHeader("Content-Type",
00518                             PromiseFlatString(
00519                               "application/x-www-form-urlencoded; charset="
00520                               + mCharset
00521                             ).get());
00522 #else
00523       mimeStream->AddHeader("Content-Type",
00524                             "application/x-www-form-urlencoded");
00525 #endif
00526       mimeStream->SetAddContentLength(PR_TRUE);
00527       mimeStream->SetData(dataStream);
00528 
00529       *aPostDataStream = mimeStream;
00530       NS_ADDREF(*aPostDataStream);
00531     }
00532 
00533   } else {
00534     //
00535     // Get the full query string
00536     //
00537     PRBool schemeIsJavaScript;
00538     rv = aURI->SchemeIs("javascript", &schemeIsJavaScript);
00539     NS_ENSURE_SUCCESS(rv, rv);
00540     if (schemeIsJavaScript) {
00541       return NS_OK;
00542     }
00543 
00544     nsCAutoString path;
00545     rv = aURI->GetPath(path);
00546     NS_ENSURE_SUCCESS(rv, rv);
00547     // Bug 42616: Trim off named anchor and save it to add later
00548     PRInt32 namedAnchorPos = path.FindChar('#');
00549     nsCAutoString namedAnchor;
00550     if (kNotFound != namedAnchorPos) {
00551       path.Right(namedAnchor, (path.Length() - namedAnchorPos));
00552       path.Truncate(namedAnchorPos);
00553     }
00554 
00555     // Chop off old query string (bug 25330, 57333)
00556     // Only do this for GET not POST (bug 41585)
00557     PRInt32 queryStart = path.FindChar('?');
00558     if (kNotFound != queryStart) {
00559       path.Truncate(queryStart);
00560     }
00561 
00562     path.Append('?');
00563     // Bug 42616: Add named anchor to end after query string
00564     path.Append(mQueryString + namedAnchor);
00565 
00566     aURI->SetPath(path);
00567   }
00568 
00569   return rv;
00570 }
00571 
00572 // i18n helper routines
00573 nsresult
00574 nsFSURLEncoded::URLEncode(const nsAString& aStr, nsCString& aEncoded)
00575 {
00576   // convert to CRLF breaks
00577   PRUnichar* convertedBuf =
00578     nsLinebreakConverter::ConvertUnicharLineBreaks(PromiseFlatString(aStr).get(),
00579                                                    nsLinebreakConverter::eLinebreakAny,
00580                                                    nsLinebreakConverter::eLinebreakNet);
00581   NS_ENSURE_TRUE(convertedBuf, NS_ERROR_OUT_OF_MEMORY);
00582 
00583   nsCAutoString encodedBuf;
00584   nsresult rv = EncodeVal(nsDependentString(convertedBuf), encodedBuf);
00585   nsMemory::Free(convertedBuf);
00586   NS_ENSURE_SUCCESS(rv, rv);
00587 
00588   char* escapedBuf = nsEscape(encodedBuf.get(), url_XPAlphas);
00589   NS_ENSURE_TRUE(escapedBuf, NS_ERROR_OUT_OF_MEMORY);
00590   aEncoded.Adopt(escapedBuf);
00591 
00592   return NS_OK;
00593 }
00594 
00595 
00596 
00601 class nsFSMultipartFormData : public nsFormSubmission
00602 {
00603 public:
00611   nsFSMultipartFormData(const nsACString& aCharset,
00612                         nsISaveAsCharset* aEncoder,
00613                         nsIFormProcessor* aFormProcessor,
00614                         PRInt32 aBidiOptions);
00615   virtual ~nsFSMultipartFormData() { }
00616  
00617   NS_DECL_ISUPPORTS_INHERITED
00618 
00619   // nsIFormSubmission
00620   virtual nsresult AddNameValuePair(nsIDOMHTMLElement* aSource,
00621                                     const nsAString& aName,
00622                                     const nsAString& aValue);
00623   virtual nsresult AddNameFilePair(nsIDOMHTMLElement* aSource,
00624                                    const nsAString& aName,
00625                                    const nsAString& aFilename,
00626                                    nsIInputStream* aStream,
00627                                    const nsACString& aContentType,
00628                                    PRBool aMoreFilesToCome);
00629   virtual PRBool AcceptsFiles() const
00630   {
00631     return PR_TRUE;
00632   }
00633 
00634   NS_IMETHOD Init();
00635 
00636 protected:
00637   // nsFormSubmission
00638   NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
00639                                   nsIInputStream** aPostDataStream);
00640 
00641   // Helpers
00645   nsresult AddPostDataStream();
00656   nsresult ProcessAndEncode(nsIDOMHTMLElement* aSource,
00657                             const nsAString& aName,
00658                             const nsAString& aValue,
00659                             nsCString& aProcessedName,
00660                             nsCString& aProcessedValue);
00661 
00662 private:
00672   PRBool mBackwardsCompatibleSubmit;
00673 
00679   nsCOMPtr<nsIMultiplexInputStream> mPostDataStream;
00680 
00688   nsCString mPostDataChunk;
00689 
00695   nsCString mBoundary;
00696 };
00697 
00698 NS_IMPL_RELEASE_INHERITED(nsFSMultipartFormData, nsFormSubmission)
00699 NS_IMPL_ADDREF_INHERITED(nsFSMultipartFormData, nsFormSubmission)
00700 NS_IMPL_QUERY_INTERFACE_INHERITED0(nsFSMultipartFormData, nsFormSubmission)
00701 
00702 //
00703 // Constructor
00704 //
00705 nsFSMultipartFormData::nsFSMultipartFormData(const nsACString& aCharset,
00706                                              nsISaveAsCharset* aEncoder,
00707                                              nsIFormProcessor* aFormProcessor,
00708                                              PRInt32 aBidiOptions)
00709     : nsFormSubmission(aCharset, aEncoder, aFormProcessor, aBidiOptions)
00710 {
00711   // XXX I can't *believe* we have a pref for this.  ifdef, anyone?
00712   mBackwardsCompatibleSubmit =
00713     nsContentUtils::GetBoolPref("browser.forms.submit.backwards_compatible");
00714 }
00715 
00716 nsresult
00717 nsFSMultipartFormData::ProcessAndEncode(nsIDOMHTMLElement* aSource,
00718                                         const nsAString& aName,
00719                                         const nsAString& aValue,
00720                                         nsCString& aProcessedName,
00721                                         nsCString& aProcessedValue)
00722 {
00723   //
00724   // Let external code process (and possibly change) value
00725   //
00726   nsAutoString processedValue;
00727   nsresult rv = ProcessValue(aSource, aName, aValue, processedValue);
00728 
00729   //
00730   // Get value
00731   //
00732   nsCAutoString encodedVal;
00733   if (NS_SUCCEEDED(rv)) {
00734     rv = EncodeVal(processedValue, encodedVal);
00735   } else {
00736     rv = EncodeVal(aValue, encodedVal);
00737   }
00738   NS_ENSURE_SUCCESS(rv, rv);
00739 
00740   //
00741   // Get name
00742   //
00743   rv  = EncodeVal(aName, aProcessedName);
00744   NS_ENSURE_SUCCESS(rv, rv);
00745 
00746 
00747   //
00748   // Convert linebreaks in value
00749   //
00750   aProcessedValue.Adopt(nsLinebreakConverter::ConvertLineBreaks(encodedVal.get(),
00751                         nsLinebreakConverter::eLinebreakAny,
00752                         nsLinebreakConverter::eLinebreakNet));
00753   return NS_OK;
00754 }
00755 
00756 //
00757 // nsIFormSubmission
00758 //
00759 nsresult
00760 nsFSMultipartFormData::AddNameValuePair(nsIDOMHTMLElement* aSource,
00761                                         const nsAString& aName,
00762                                         const nsAString& aValue)
00763 {
00764   nsCAutoString nameStr;
00765   nsCString valueStr;
00766   nsresult rv = ProcessAndEncode(aSource, aName, aValue, nameStr, valueStr);
00767   NS_ENSURE_SUCCESS(rv, rv);
00768 
00769   //
00770   // Make MIME block for name/value pair
00771   //
00772   // XXX: name parameter should be encoded per RFC 2231
00773   // RFC 2388 specifies that RFC 2047 be used, but I think it's not 
00774   // consistent with MIME standard.
00775   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
00776                  + NS_LITERAL_CSTRING(CRLF)
00777                  + NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
00778                  + nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
00779                  + valueStr + NS_LITERAL_CSTRING(CRLF);
00780 
00781   return NS_OK;
00782 }
00783 
00784 nsresult
00785 nsFSMultipartFormData::AddNameFilePair(nsIDOMHTMLElement* aSource,
00786                                        const nsAString& aName,
00787                                        const nsAString& aFilename,
00788                                        nsIInputStream* aStream,
00789                                        const nsACString& aContentType,
00790                                        PRBool aMoreFilesToCome)
00791 {
00792   nsCAutoString nameStr;
00793   nsCAutoString filenameStr;
00794   nsresult rv = ProcessAndEncode(aSource, aName, aFilename, nameStr, filenameStr);
00795   NS_ENSURE_SUCCESS(rv, rv);
00796 
00797   //
00798   // Make MIME block for name/value pair
00799   //
00800   // more appropriate than always using binary?
00801   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
00802                  + NS_LITERAL_CSTRING(CRLF);
00803   if (!mBackwardsCompatibleSubmit) {
00804     // XXX Is there any way to tell when "8bit" or "7bit" etc may be
00805     mPostDataChunk +=
00806           NS_LITERAL_CSTRING("Content-Transfer-Encoding: binary" CRLF);
00807   }
00808   // XXX: name/filename parameter should be encoded per RFC 2231
00809   // RFC 2388 specifies that RFC 2047 be used, but I think it's not 
00810   // consistent with the MIME standard.
00811   mPostDataChunk +=
00812          NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
00813        + nameStr + NS_LITERAL_CSTRING("\"; filename=\"")
00814        + filenameStr + NS_LITERAL_CSTRING("\"" CRLF)
00815        + NS_LITERAL_CSTRING("Content-Type: ") + aContentType
00816        + NS_LITERAL_CSTRING(CRLF CRLF);
00817 
00818   //
00819   // Add the file to the stream
00820   //
00821   if (aStream) {
00822     // We need to dump the data up to this point into the POST data stream here,
00823     // since we're about to add the file input stream
00824     AddPostDataStream();
00825 
00826     mPostDataStream->AppendStream(aStream);
00827   }
00828 
00829   //
00830   // CRLF after file
00831   //
00832   mPostDataChunk.AppendLiteral(CRLF);
00833 
00834   return NS_OK;
00835 }
00836 
00837 //
00838 // nsFormSubmission
00839 //
00840 NS_IMETHODIMP
00841 nsFSMultipartFormData::Init()
00842 {
00843   nsresult rv;
00844 
00845   //
00846   // Create the POST stream
00847   //
00848   mPostDataStream =
00849     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1", &rv);
00850   NS_ENSURE_SUCCESS(rv, rv);
00851   if (!mPostDataStream) {
00852     return NS_ERROR_OUT_OF_MEMORY;
00853   }
00854 
00855   //
00856   // Build boundary
00857   //
00858   mBoundary.AssignLiteral("---------------------------");
00859   mBoundary.AppendInt(rand());
00860   mBoundary.AppendInt(rand());
00861   mBoundary.AppendInt(rand());
00862 
00863   return NS_OK;
00864 }
00865 
00866 NS_IMETHODIMP
00867 nsFSMultipartFormData::GetEncodedSubmission(nsIURI* aURI,
00868                                             nsIInputStream** aPostDataStream)
00869 {
00870   nsresult rv;
00871 
00872   //
00873   // Finish data
00874   //
00875   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
00876                   + NS_LITERAL_CSTRING("--" CRLF);
00877 
00878   //
00879   // Add final data input stream
00880   //
00881   AddPostDataStream();
00882 
00883   //
00884   // Make header
00885   //
00886   nsCOMPtr<nsIMIMEInputStream> mimeStream
00887     = do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv);
00888   NS_ENSURE_SUCCESS(rv, rv);
00889 
00890   nsCAutoString boundaryHeaderValue(
00891     NS_LITERAL_CSTRING("multipart/form-data; boundary=") + mBoundary);
00892 
00893   mimeStream->AddHeader("Content-Type", boundaryHeaderValue.get());
00894   mimeStream->SetAddContentLength(PR_TRUE);
00895   mimeStream->SetData(mPostDataStream);
00896 
00897   *aPostDataStream = mimeStream;
00898 
00899   NS_ADDREF(*aPostDataStream);
00900 
00901   return NS_OK;
00902 }
00903 
00904 nsresult
00905 nsFSMultipartFormData::AddPostDataStream()
00906 {
00907   nsresult rv = NS_OK;
00908   
00909   nsCOMPtr<nsIInputStream> postDataChunkStream;
00910   rv = NS_NewCStringInputStream(getter_AddRefs(postDataChunkStream),
00911                                 mPostDataChunk);
00912   NS_ASSERTION(postDataChunkStream, "Could not open a stream for POST!");
00913   if (postDataChunkStream) {
00914     mPostDataStream->AppendStream(postDataChunkStream);
00915   }
00916 
00917   mPostDataChunk.Truncate();
00918 
00919   return rv;
00920 }
00921 
00922 
00923 //
00924 // CLASS nsFSTextPlain
00925 //
00926 class nsFSTextPlain : public nsFormSubmission
00927 {
00928 public:
00929   nsFSTextPlain(const nsACString& aCharset,
00930                 nsISaveAsCharset* aEncoder,
00931                 nsIFormProcessor* aFormProcessor,
00932                 PRInt32 aBidiOptions)
00933     : nsFormSubmission(aCharset, aEncoder, aFormProcessor, aBidiOptions)
00934   {
00935   }
00936   virtual ~nsFSTextPlain()
00937   {
00938   }
00939 
00940   NS_DECL_ISUPPORTS_INHERITED
00941 
00942   // nsIFormSubmission
00943   virtual nsresult AddNameValuePair(nsIDOMHTMLElement* aSource,
00944                                     const nsAString& aName,
00945                                     const nsAString& aValue);
00946   virtual nsresult AddNameFilePair(nsIDOMHTMLElement* aSource,
00947                                    const nsAString& aName,
00948                                    const nsAString& aFilename,
00949                                    nsIInputStream* aStream,
00950                                    const nsACString& aContentType,
00951                                    PRBool aMoreFilesToCome);
00952 
00953   NS_IMETHOD Init();
00954 
00955 protected:
00956   // nsFormSubmission
00957   NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
00958                                   nsIInputStream** aPostDataStream);
00959   virtual PRBool AcceptsFiles() const
00960   {
00961     return PR_FALSE;
00962   }
00963 
00964 private:
00965   nsString mBody;
00966 };
00967 
00968 NS_IMPL_RELEASE_INHERITED(nsFSTextPlain, nsFormSubmission)
00969 NS_IMPL_ADDREF_INHERITED(nsFSTextPlain, nsFormSubmission)
00970 NS_IMPL_QUERY_INTERFACE_INHERITED0(nsFSTextPlain, nsFormSubmission)
00971 
00972 nsresult
00973 nsFSTextPlain::AddNameValuePair(nsIDOMHTMLElement* aSource,
00974                                 const nsAString& aName,
00975                                 const nsAString& aValue)
00976 {
00977   //
00978   // Let external code process (and possibly change) value
00979   //
00980   nsString processedValue;
00981   nsresult rv = ProcessValue(aSource, aName, aValue, processedValue);
00982 
00983   // XXX This won't work well with a name like "a=b" or "a\nb" but I suppose
00984   // text/plain doesn't care about that.  Parsers aren't built for escaped
00985   // values so we'll have to live with it.
00986   if (NS_SUCCEEDED(rv)) {
00987     mBody.Append(aName + NS_LITERAL_STRING("=") + processedValue +
00988                  NS_LITERAL_STRING(CRLF));
00989 
00990   } else {
00991     mBody.Append(aName + NS_LITERAL_STRING("=") + aValue +
00992                  NS_LITERAL_STRING(CRLF));
00993   }
00994 
00995   return NS_OK;
00996 }
00997 
00998 nsresult
00999 nsFSTextPlain::AddNameFilePair(nsIDOMHTMLElement* aSource,
01000                                const nsAString& aName,
01001                                const nsAString& aFilename,
01002                                nsIInputStream* aStream,
01003                                const nsACString& aContentType,
01004                                PRBool aMoreFilesToCome)
01005 {
01006   AddNameValuePair(aSource,aName,aFilename);
01007   return NS_OK;
01008 }
01009 
01010 //
01011 // nsFormSubmission
01012 //
01013 NS_IMETHODIMP
01014 nsFSTextPlain::Init()
01015 {
01016   mBody.Truncate();
01017   return NS_OK;
01018 }
01019 
01020 NS_IMETHODIMP
01021 nsFSTextPlain::GetEncodedSubmission(nsIURI* aURI,
01022                                     nsIInputStream** aPostDataStream)
01023 {
01024   nsresult rv = NS_OK;
01025 
01026   // XXX HACK We are using the standard URL mechanism to give the body to the
01027   // mailer instead of passing the post data stream to it, since that sounds
01028   // hard.
01029   PRBool isMailto = PR_FALSE;
01030   aURI->SchemeIs("mailto", &isMailto);
01031   if (isMailto) {
01032     nsCAutoString path;
01033     rv = aURI->GetPath(path);
01034     NS_ENSURE_SUCCESS(rv, rv);
01035 
01036     HandleMailtoSubject(path);
01037 
01038     // Append the body to and force-plain-text args to the mailto line
01039     char* escapedBuf = nsEscape(NS_ConvertUTF16toUTF8(mBody).get(),
01040                                 url_XAlphas);
01041     NS_ENSURE_TRUE(escapedBuf, NS_ERROR_OUT_OF_MEMORY);
01042     nsCString escapedBody;
01043     escapedBody.Adopt(escapedBuf);
01044 
01045     path += NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody;
01046 
01047     rv = aURI->SetPath(path);
01048 
01049   } else {
01050 
01051     // Create data stream
01052     nsCOMPtr<nsIInputStream> bodyStream;
01053     rv = NS_NewStringInputStream(getter_AddRefs(bodyStream),
01054                                           mBody);
01055     if (!bodyStream) {
01056       return NS_ERROR_OUT_OF_MEMORY;
01057     }
01058 
01059     // Create mime stream with headers and such
01060     nsCOMPtr<nsIMIMEInputStream> mimeStream
01061         = do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv);
01062     NS_ENSURE_SUCCESS(rv, rv);
01063 
01064     mimeStream->AddHeader("Content-Type", "text/plain");
01065     mimeStream->SetAddContentLength(PR_TRUE);
01066     mimeStream->SetData(bodyStream);
01067     CallQueryInterface(mimeStream, aPostDataStream);
01068     NS_ADDREF(*aPostDataStream);
01069   }
01070 
01071   return rv;
01072 }
01073 
01074 
01075 //
01076 // CLASS nsFormSubmission
01077 //
01078 
01079 //
01080 // nsISupports stuff
01081 //
01082 
01083 NS_IMPL_ADDREF(nsFormSubmission)
01084 NS_IMPL_RELEASE(nsFormSubmission)
01085 
01086 NS_INTERFACE_MAP_BEGIN(nsFormSubmission)
01087   NS_INTERFACE_MAP_ENTRY(nsIFormSubmission)
01088   NS_INTERFACE_MAP_ENTRY(nsISupports)
01089 NS_INTERFACE_MAP_END
01090 
01091 
01092 // JBK moved from nsFormFrame - bug 34297
01093 // submission
01094 
01095 static nsresult
01096 SendJSWarning(nsIContent* aContent,
01097                const char* aWarningName)
01098 {
01099   return SendJSWarning(aContent, aWarningName, nsnull, 0);
01100 }
01101 
01102 static nsresult
01103 SendJSWarning(nsIContent* aContent,
01104                const char* aWarningName,
01105                const nsAFlatString& aWarningArg1)
01106 {
01107   const PRUnichar* formatStrings[1] = { aWarningArg1.get() };
01108   return SendJSWarning(aContent, aWarningName, formatStrings, 1);
01109 }
01110 
01111 static nsresult
01112 SendJSWarning(nsIContent* aContent,
01113               const char* aWarningName,
01114               const PRUnichar** aWarningArgs, PRUint32 aWarningArgsLen)
01115 {
01116   // Get the document URL to use as the filename
01117 
01118   nsIDocument* document = aContent->GetDocument();
01119   nsIURI *documentURI = nsnull;
01120   if (document) {
01121     documentURI = document->GetDocumentURI();
01122     NS_ENSURE_TRUE(documentURI, NS_ERROR_UNEXPECTED);
01123   }
01124 
01125   return nsContentUtils::ReportToConsole(nsContentUtils::eFORMS_PROPERTIES,
01126                                          aWarningName,
01127                                          aWarningArgs, aWarningArgsLen,
01128                                          documentURI,
01129                                          EmptyString(), 0, 0,
01130                                          nsIScriptError::warningFlag,
01131                                          "HTML");
01132 }
01133 
01134 nsresult
01135 GetSubmissionFromForm(nsGenericHTMLElement* aForm,
01136                       nsPresContext* aPresContext,
01137                       nsIFormSubmission** aFormSubmission)
01138 {
01139   nsresult rv = NS_OK;
01140 
01141   //
01142   // Get all the information necessary to encode the form data
01143   //
01144 
01145   // Get BIDI options
01146   PRUint8 ctrlsModAtSubmit = 0;
01147   PRUint32 bidiOptions = aPresContext->GetBidi();
01148   ctrlsModAtSubmit = GET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions);
01149 
01150   // Get encoding type (default: urlencoded)
01151   PRInt32 enctype = NS_FORM_ENCTYPE_URLENCODED;
01152   nsFormSubmission::GetEnumAttr(aForm, nsHTMLAtoms::enctype, &enctype);
01153 
01154   // Get method (default: GET)
01155   PRInt32 method = NS_FORM_METHOD_GET;
01156   nsFormSubmission::GetEnumAttr(aForm, nsHTMLAtoms::method, &method);
01157 
01158   // Get charset
01159   nsCAutoString charset;
01160   nsFormSubmission::GetSubmitCharset(aForm, ctrlsModAtSubmit, charset);
01161 
01162   // Get unicode encoder
01163   nsCOMPtr<nsISaveAsCharset> encoder;
01164   nsFormSubmission::GetEncoder(aForm, aPresContext, charset,
01165                                getter_AddRefs(encoder));
01166 
01167   // Get form processor
01168   nsCOMPtr<nsIFormProcessor> formProcessor =
01169     do_GetService(kFormProcessorCID, &rv);
01170 
01171   //
01172   // Choose encoder
01173   //
01174   // If enctype=multipart/form-data and method=post, do multipart
01175   // Else do URL encoded
01176   // NOTE:
01177   // The rule used to be, if enctype=multipart/form-data, do multipart
01178   // Else do URL encoded
01179   if (method == NS_FORM_METHOD_POST &&
01180       enctype == NS_FORM_ENCTYPE_MULTIPART) {
01181     *aFormSubmission = new nsFSMultipartFormData(charset, encoder,
01182                                                  formProcessor, bidiOptions);
01183   } else if (method == NS_FORM_METHOD_POST &&
01184              enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
01185     *aFormSubmission = new nsFSTextPlain(charset, encoder,
01186                                          formProcessor, bidiOptions);
01187   } else {
01188     if (enctype == NS_FORM_ENCTYPE_MULTIPART ||
01189         enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
01190       nsAutoString enctypeStr;
01191       aForm->GetAttr(kNameSpaceID_None, nsHTMLAtoms::enctype, enctypeStr);
01192       SendJSWarning(aForm, "ForgotPostWarning", PromiseFlatString(enctypeStr));
01193     }
01194     *aFormSubmission = new nsFSURLEncoded(charset, encoder,
01195                                           formProcessor, bidiOptions, method);
01196   }
01197   NS_ENSURE_TRUE(*aFormSubmission, NS_ERROR_OUT_OF_MEMORY);
01198   NS_ADDREF(*aFormSubmission);
01199 
01200 
01201   // This ASSUMES that all encodings above inherit from nsFormSubmission, which
01202   // they currently do.  If that changes, change this too.
01203   NS_STATIC_CAST(nsFormSubmission*, *aFormSubmission)->Init();
01204 
01205   return NS_OK;
01206 }
01207 
01208 nsresult
01209 nsFormSubmission::SubmitTo(nsIURI* aActionURI, const nsAString& aTarget,
01210                            nsIContent* aSource, nsPresContext* aPresContext,
01211                            nsIDocShell** aDocShell, nsIRequest** aRequest)
01212 {
01213   nsresult rv;
01214 
01215   //
01216   // Finish encoding (get post data stream and URI)
01217   //
01218   nsCOMPtr<nsIInputStream> postDataStream;
01219   rv = GetEncodedSubmission(aActionURI, getter_AddRefs(postDataStream));
01220   NS_ENSURE_SUCCESS(rv, rv);
01221 
01222   //
01223   // Actually submit the data
01224   //
01225   nsILinkHandler *handler = aPresContext->GetLinkHandler();
01226   NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE);
01227 
01228   return handler->OnLinkClickSync(aSource, eLinkVerb_Replace,
01229                                   aActionURI,
01230                                   PromiseFlatString(aTarget).get(),
01231                                   postDataStream, nsnull,
01232                                   aDocShell, aRequest);
01233 }
01234 
01235 // JBK moved from nsFormFrame - bug 34297
01236 // static
01237 void
01238 nsFormSubmission::GetSubmitCharset(nsGenericHTMLElement* aForm,
01239                                    PRUint8 aCtrlsModAtSubmit,
01240                                    nsACString& oCharset)
01241 {
01242   oCharset.AssignLiteral("UTF-8"); // default to utf-8
01243 
01244   nsresult rv = NS_OK;
01245   nsAutoString acceptCharsetValue;
01246   aForm->GetAttr(kNameSpaceID_None, nsHTMLAtoms::acceptcharset,
01247                  acceptCharsetValue);
01248 
01249   PRInt32 charsetLen = acceptCharsetValue.Length();
01250   if (charsetLen > 0) {
01251     PRInt32 offset=0;
01252     PRInt32 spPos=0;
01253     // get charset from charsets one by one
01254     nsCOMPtr<nsICharsetAlias> calias(do_GetService(kCharsetAliasCID, &rv));
01255     if (NS_FAILED(rv)) {
01256       return;
01257     }
01258     if (calias) {
01259       do {
01260         spPos = acceptCharsetValue.FindChar(PRUnichar(' '), offset);
01261         PRInt32 cnt = ((-1==spPos)?(charsetLen-offset):(spPos-offset));
01262         if (cnt > 0) {
01263           nsAutoString uCharset;
01264           acceptCharsetValue.Mid(uCharset, offset, cnt);
01265 
01266           if (NS_SUCCEEDED(calias->
01267                            GetPreferred(NS_LossyConvertUTF16toASCII(uCharset),
01268                                         oCharset)))
01269             return;
01270         }
01271         offset = spPos + 1;
01272       } while (spPos != -1);
01273     }
01274   }
01275   // if there are no accept-charset or all the charset are not supported
01276   // Get the charset from document
01277   nsIDocument* doc = aForm->GetDocument();
01278   if (doc) {
01279     oCharset = doc->GetDocumentCharacterSet();
01280   }
01281 
01282   if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
01283      && oCharset.Equals(NS_LITERAL_CSTRING("windows-1256"),
01284                         nsCaseInsensitiveCStringComparator())) {
01285 //Mohamed
01286     oCharset.AssignLiteral("IBM864");
01287   }
01288   else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_LOGICAL
01289           && oCharset.Equals(NS_LITERAL_CSTRING("IBM864"),
01290                              nsCaseInsensitiveCStringComparator())) {
01291     oCharset.AssignLiteral("IBM864i");
01292   }
01293   else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
01294           && oCharset.Equals(NS_LITERAL_CSTRING("ISO-8859-6"),
01295                              nsCaseInsensitiveCStringComparator())) {
01296     oCharset.AssignLiteral("IBM864");
01297   }
01298   else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
01299           && oCharset.Equals(NS_LITERAL_CSTRING("UTF-8"),
01300                              nsCaseInsensitiveCStringComparator())) {
01301     oCharset.AssignLiteral("IBM864");
01302   }
01303 
01304 }
01305 
01306 // JBK moved from nsFormFrame - bug 34297
01307 // static
01308 nsresult
01309 nsFormSubmission::GetEncoder(nsGenericHTMLElement* aForm,
01310                              nsPresContext* aPresContext,
01311                              const nsACString& aCharset,
01312                              nsISaveAsCharset** aEncoder)
01313 {
01314   *aEncoder = nsnull;
01315   nsresult rv = NS_OK;
01316 
01317   nsCAutoString charset(aCharset);
01318   // canonical name is passed so that we just have to check against
01319   // *our* canonical names listed in charsetaliases.properties
01320   if (charset.EqualsLiteral("ISO-8859-1")) {
01321     charset.AssignLiteral("windows-1252");
01322   }
01323 
01324   // use UTF-8 for UTF-16* and UTF-32* (per WHATWG and existing practice of
01325   // MS IE/Opera). 
01326   if (StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-16")) || 
01327       StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-32"))) {
01328     charset.AssignLiteral("UTF-8");
01329   }
01330 
01331   rv = CallCreateInstance( NS_SAVEASCHARSET_CONTRACTID, aEncoder);
01332   NS_ASSERTION(NS_SUCCEEDED(rv), "create nsISaveAsCharset failed");
01333   NS_ENSURE_SUCCESS(rv, rv);
01334 
01335   rv = (*aEncoder)->Init(charset.get(),
01336                          (nsISaveAsCharset::attr_EntityAfterCharsetConv + 
01337                           nsISaveAsCharset::attr_FallbackDecimalNCR),
01338                          0);
01339   NS_ASSERTION(NS_SUCCEEDED(rv), "initialize nsISaveAsCharset failed");
01340   NS_ENSURE_SUCCESS(rv, rv);
01341 
01342   return NS_OK;
01343 }
01344 
01345 // i18n helper routines
01346 nsresult
01347 nsFormSubmission::UnicodeToNewBytes(const nsAString& aStr, 
01348                                     nsISaveAsCharset* aEncoder,
01349                                     nsACString& aOut)
01350 {
01351   PRUint8 ctrlsModAtSubmit = GET_BIDI_OPTION_CONTROLSTEXTMODE(mBidiOptions);
01352   PRUint8 textDirAtSubmit = GET_BIDI_OPTION_DIRECTION(mBidiOptions);
01353   //ahmed 15-1
01354   nsAutoString newBuffer;
01355   //This condition handle the RTL,LTR for a logical file
01356   if (ctrlsModAtSubmit == IBMBIDI_CONTROLSTEXTMODE_VISUAL
01357      && mCharset.Equals(NS_LITERAL_CSTRING("windows-1256"),
01358                         nsCaseInsensitiveCStringComparator())) {
01359     Conv_06_FE_WithReverse(nsString(aStr),
01360                            newBuffer,
01361                            textDirAtSubmit);
01362   }
01363   else if (ctrlsModAtSubmit == IBMBIDI_CONTROLSTEXTMODE_LOGICAL
01364           && mCharset.Equals(NS_LITERAL_CSTRING("IBM864"),
01365                              nsCaseInsensitiveCStringComparator())) {
01366     //For 864 file, When it is logical, if LTR then only convert
01367     //If RTL will mak a reverse for the buffer
01368     Conv_FE_06(nsString(aStr), newBuffer);
01369     if (textDirAtSubmit == 2) { //RTL
01370     //Now we need to reverse the Buffer, it is by searching the buffer
01371       PRInt32 len = newBuffer.Length();
01372       PRUint32 z = 0;
01373       nsAutoString temp;
01374       temp.SetLength(len);
01375       while (--len >= 0)
01376         temp.SetCharAt(newBuffer.CharAt(len), z++);
01377       newBuffer = temp;
01378     }
01379   }
01380   else if (ctrlsModAtSubmit == IBMBIDI_CONTROLSTEXTMODE_VISUAL
01381           && mCharset.Equals(NS_LITERAL_CSTRING("IBM864"),
01382                              nsCaseInsensitiveCStringComparator())
01383                   && textDirAtSubmit == IBMBIDI_TEXTDIRECTION_RTL) {
01384 
01385     Conv_FE_06(nsString(aStr), newBuffer);
01386     //Now we need to reverse the Buffer, it is by searching the buffer
01387     PRInt32 len = newBuffer.Length();
01388     PRUint32 z = 0;
01389     nsAutoString temp;
01390     temp.SetLength(len);
01391     while (--len >= 0)
01392       temp.SetCharAt(newBuffer.CharAt(len), z++);
01393     newBuffer = temp;
01394   }
01395   else {
01396     newBuffer = aStr;
01397   }
01398 
01399   nsXPIDLCString res;
01400   if (!newBuffer.IsEmpty()) {
01401     aOut.Truncate();
01402     nsresult rv = aEncoder->Convert(newBuffer.get(), getter_Copies(res));
01403     NS_ENSURE_SUCCESS(rv, rv);
01404   }
01405 
01406   aOut = res;
01407   return NS_OK;
01408 }
01409 
01410 
01411 // static
01412 void
01413 nsFormSubmission::GetEnumAttr(nsGenericHTMLElement* aContent,
01414                               nsIAtom* atom, PRInt32* aValue)
01415 {
01416   const nsAttrValue* value = aContent->GetParsedAttr(atom);
01417   if (value && value->Type() == nsAttrValue::eEnum) {
01418     *aValue = value->GetEnumValue();
01419   }
01420 }
01421 
01422 nsresult
01423 nsFormSubmission::EncodeVal(const nsAString& aStr, nsACString& aOut)
01424 {
01425   NS_ASSERTION(mEncoder, "Encoder not available. Losing data !");
01426   if (mEncoder)
01427     return UnicodeToNewBytes(aStr, mEncoder, aOut);
01428 
01429   // fall back to UTF-8
01430   CopyUTF16toUTF8(aStr, aOut);
01431   return NS_OK;
01432 }
01433 
01434 nsresult
01435 nsFormSubmission::ProcessValue(nsIDOMHTMLElement* aSource,
01436                                const nsAString& aName, const nsAString& aValue,
01437                                nsAString& aResult) 
01438 {
01439   // Hijack _charset_ (hidden inputs only) for internationalization (bug 18643)
01440   if (aName.EqualsLiteral("_charset_")) {
01441     nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aSource);
01442     if (formControl && formControl->GetType() == NS_FORM_INPUT_HIDDEN) {
01443         CopyASCIItoUTF16(mCharset, aResult);
01444         return NS_OK;
01445     }
01446   }
01447 
01448   nsresult rv = NS_OK;
01449   aResult = aValue;
01450   if (mFormProcessor) {
01451     rv = mFormProcessor->ProcessValue(aSource, aName, aResult);
01452     NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to Notify form process observer");
01453   }
01454 
01455   return rv;
01456 }