Back to index

lightning-sunbird  0.9+nobinonly
mimeunty.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "mimeunty.h"
00039 #include "prmem.h"
00040 #include "plstr.h"
00041 #include "nsCRT.h"
00042 #include "prlog.h"
00043 #include "nsMimeTypes.h"
00044 #include "msgCore.h"
00045 #include "nsMimeStringResources.h"
00046 
00047 #define MIME_SUPERCLASS mimeContainerClass
00048 MimeDefClass(MimeUntypedText, MimeUntypedTextClass,
00049                       mimeUntypedTextClass, &MIME_SUPERCLASS);
00050 
00051 static int MimeUntypedText_initialize (MimeObject *);
00052 static void MimeUntypedText_finalize (MimeObject *);
00053 static int MimeUntypedText_parse_begin (MimeObject *);
00054 static int MimeUntypedText_parse_line (char *, PRInt32, MimeObject *);
00055 
00056 static int MimeUntypedText_open_subpart (MimeObject *obj,
00057                                                                        MimeUntypedTextSubpartType ttype,
00058                                                                        const char *type,
00059                                                                        const char *enc,
00060                                                                        const char *name,
00061                                                                        const char *desc);
00062 static int MimeUntypedText_close_subpart (MimeObject *obj);
00063 
00064 static PRBool MimeUntypedText_uu_begin_line_p(const char *line, PRInt32 length,
00065                                                                                 MimeDisplayOptions *opt,
00066                                                                                 char **type_ret,
00067                                                                                 char **name_ret);
00068 static PRBool MimeUntypedText_uu_end_line_p(const char *line, PRInt32 length);
00069 
00070 static PRBool MimeUntypedText_yenc_begin_line_p(const char *line, PRInt32 length,
00071                                                                                 MimeDisplayOptions *opt,
00072                                                                                 char **type_ret,
00073                                                                                 char **name_ret);
00074 static PRBool MimeUntypedText_yenc_end_line_p(const char *line, PRInt32 length);
00075 
00076 static PRBool MimeUntypedText_binhex_begin_line_p(const char *line,
00077                                                                                        PRInt32 length,
00078                                                                                        MimeDisplayOptions *opt);
00079 static PRBool MimeUntypedText_binhex_end_line_p(const char *line,
00080                                                                                      PRInt32 length);
00081 
00082 static int
00083 MimeUntypedTextClassInitialize(MimeUntypedTextClass *clazz)
00084 {
00085   MimeObjectClass *oclass = (MimeObjectClass *) clazz;
00086   PR_ASSERT(!oclass->class_initialized);
00087   oclass->initialize  = MimeUntypedText_initialize;
00088   oclass->finalize    = MimeUntypedText_finalize;
00089   oclass->parse_begin = MimeUntypedText_parse_begin;
00090   oclass->parse_line  = MimeUntypedText_parse_line;
00091   return 0;
00092 }
00093 
00094 
00095 static int
00096 MimeUntypedText_initialize (MimeObject *object)
00097 {
00098   return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
00099 }
00100 
00101 static void
00102 MimeUntypedText_finalize (MimeObject *object)
00103 {
00104   MimeUntypedText *uty = (MimeUntypedText *) object;
00105 
00106   if (uty->open_hdrs)
00107        {
00108          /* Oops, those shouldn't still be here... */
00109          MimeHeaders_free(uty->open_hdrs);
00110          uty->open_hdrs = 0;
00111        }
00112 
00113   /* What about the open_subpart?  We're gonna have to assume that it
00114         is also on the MimeContainer->children list, and will get cleaned
00115         up by that class. */
00116 
00117   ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
00118 }
00119 
00120 static int
00121 MimeUntypedText_parse_begin (MimeObject *obj)
00122 {
00123   return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
00124 }
00125 
00126 static int
00127 MimeUntypedText_parse_line (char *line, PRInt32 length, MimeObject *obj)
00128 {
00129   MimeUntypedText *uty = (MimeUntypedText *) obj;
00130   int status = 0;
00131   char *name = 0, *type = 0;
00132   PRBool begin_line_p = PR_FALSE;
00133 
00134   PR_ASSERT(line && *line);
00135   if (!line || !*line) return -1;
00136 
00137   /* If we're supposed to write this object, but aren't supposed to convert
00138         it to HTML, simply pass it through unaltered. */
00139   if (obj->output_p &&
00140          obj->options &&
00141          !obj->options->write_html_p &&
00142          obj->options->output_fn)
00143        return MimeObject_write(obj, line, length, PR_TRUE);
00144 
00145 
00146   /* Open a new sub-part if this line demands it.
00147    */
00148   if (line[0] == 'b' &&
00149          MimeUntypedText_uu_begin_line_p(line, length, obj->options,
00150                                                                  &type, &name))
00151        {
00152          /* Close the old part and open a new one. */
00153          status = MimeUntypedText_open_subpart (obj,
00154                                                                               MimeUntypedTextSubpartTypeUUE,
00155                                                                               type, ENCODING_UUENCODE,
00156                                                                               name, NULL);
00157          PR_FREEIF(name);
00158          PR_FREEIF(type);
00159          if (status < 0) return status;
00160          begin_line_p = PR_TRUE;
00161        }
00162 
00163   else if (line[0] == '=' &&
00164          MimeUntypedText_yenc_begin_line_p(line, length, obj->options,
00165                                                                  &type, &name))
00166        {
00167          /* Close the old part and open a new one. */
00168          status = MimeUntypedText_open_subpart (obj,
00169                                                                               MimeUntypedTextSubpartTypeYEnc,
00170                                                                               type, ENCODING_YENCODE,
00171                                                                               name, NULL);
00172          PR_FREEIF(name);
00173          PR_FREEIF(type);
00174          if (status < 0) return status;
00175          begin_line_p = PR_TRUE;
00176        }
00177 
00178   else if (line[0] == '(' && line[1] == 'T' &&
00179                  MimeUntypedText_binhex_begin_line_p(line, length, obj->options))
00180        {
00181          /* Close the old part and open a new one. */
00182          status = MimeUntypedText_open_subpart (obj,
00183                                                                               MimeUntypedTextSubpartTypeBinhex,
00184                                                                               APPLICATION_BINHEX, NULL,
00185                                                                               NULL, NULL);
00186          if (status < 0) return status;
00187          begin_line_p = PR_TRUE;
00188        }
00189 
00190   /* Open a text/plain sub-part if there is no sub-part open.
00191    */
00192   if (!uty->open_subpart)
00193        {
00194     // rhp: If we get here and we are being fed a line ending, we should
00195     // just eat it and continue and if we really get more data, we'll open
00196     // up the subpart then.
00197     //
00198     if (line[0] == nsCRT::CR) return 0;
00199     if (line[0] == nsCRT::LF) return 0;
00200 
00201          PR_ASSERT(!begin_line_p);
00202          status = MimeUntypedText_open_subpart (obj,
00203                                                                               MimeUntypedTextSubpartTypeText,
00204                                                                               TEXT_PLAIN, NULL, NULL, NULL);
00205          PR_ASSERT(uty->open_subpart);
00206          if (!uty->open_subpart) return -1;
00207          if (status < 0) return status;
00208        }
00209 
00210   /* Hand this line to the currently-open sub-part.
00211    */
00212   status = uty->open_subpart->clazz->parse_buffer(line, length,
00213                                                                                       uty->open_subpart);
00214   if (status < 0) return status;
00215 
00216   /* Close this sub-part if this line demands it.
00217    */
00218   if (begin_line_p)
00219        ;
00220   else if (line[0] == 'e' &&
00221                  uty->type == MimeUntypedTextSubpartTypeUUE &&
00222                  MimeUntypedText_uu_end_line_p(line, length))
00223        {
00224          status = MimeUntypedText_close_subpart (obj);
00225          if (status < 0) return status;
00226          NS_ASSERTION(!uty->open_subpart, "no open subpart");
00227        }
00228   else if (line[0] == '=' &&
00229                  uty->type == MimeUntypedTextSubpartTypeYEnc &&
00230                  MimeUntypedText_yenc_end_line_p(line, length))
00231        {
00232          status = MimeUntypedText_close_subpart (obj);
00233          if (status < 0) return status;
00234          NS_ASSERTION(!uty->open_subpart, "no open subpart");
00235        }
00236   else if (uty->type == MimeUntypedTextSubpartTypeBinhex &&
00237                  MimeUntypedText_binhex_end_line_p(line, length))
00238        {
00239          status = MimeUntypedText_close_subpart (obj);
00240          if (status < 0) return status;
00241          NS_ASSERTION(!uty->open_subpart, "no open subpart");
00242        }
00243 
00244   return 0;
00245 }
00246 
00247 
00248 static int
00249 MimeUntypedText_close_subpart (MimeObject *obj)
00250 {
00251   MimeUntypedText *uty = (MimeUntypedText *) obj;
00252   int status;
00253 
00254   if (uty->open_subpart)
00255        {
00256          status = uty->open_subpart->clazz->parse_eof(uty->open_subpart, PR_FALSE);
00257          uty->open_subpart = 0;
00258 
00259          PR_ASSERT(uty->open_hdrs);
00260          if (uty->open_hdrs)
00261               {
00262                 MimeHeaders_free(uty->open_hdrs);
00263                 uty->open_hdrs = 0;
00264               }
00265          uty->type = MimeUntypedTextSubpartTypeText;
00266          if (status < 0) return status;
00267 
00268          /* Never put out a separator between sub-parts of UntypedText.
00269                (This bypasses the rule that text/plain subparts always
00270                have separators before and after them.)
00271                */
00272          if (obj->options && obj->options->state)
00273               obj->options->state->separator_suppressed_p = PR_TRUE;
00274        }
00275 
00276   PR_ASSERT(!uty->open_hdrs);
00277   return 0;
00278 }
00279 
00280 static int
00281 MimeUntypedText_open_subpart (MimeObject *obj,
00282                                                    MimeUntypedTextSubpartType ttype,
00283                                                    const char *type,
00284                                                    const char *enc,
00285                                                    const char *name,
00286                                                    const char *desc)
00287 {
00288   MimeUntypedText *uty = (MimeUntypedText *) obj;
00289   int status = 0;
00290   char *h = 0;
00291 
00292   if (!type || !*type || !nsCRT::strcasecmp(type, UNKNOWN_CONTENT_TYPE))
00293        type = APPLICATION_OCTET_STREAM;
00294   if (enc && !*enc)
00295        enc = 0;
00296   if (desc && !*desc)
00297        desc = 0;
00298   if (name && !*name)
00299        name = 0;
00300 
00301   if (uty->open_subpart)
00302        {
00303          status = MimeUntypedText_close_subpart (obj);
00304          if (status < 0) return status;
00305        }
00306   NS_ASSERTION(!uty->open_subpart, "no open subpart");
00307   NS_ASSERTION(!uty->open_hdrs, "no open headers");
00308 
00309   /* To make one of these implicitly-typed sub-objects, we make up a fake
00310         header block, containing only the minimum number of MIME headers needed.
00311         We could do most of this (Type and Encoding) by making a null header
00312         block, and simply setting obj->content_type and obj->encoding; but making
00313         a fake header block is better for two reasons: first, it means that
00314         something will actually be displayed when in `Show All Headers' mode;
00315         and second, it's the only way to communicate the filename parameter,
00316         aside from adding a new slot to MimeObject (which is something to be
00317         avoided when possible.)
00318    */
00319 
00320   uty->open_hdrs = MimeHeaders_new();
00321   if (!uty->open_hdrs) return MIME_OUT_OF_MEMORY;
00322 
00323   PRUint32 hlen = strlen(type) +
00324                                           (enc ? strlen(enc) : 0) +
00325                                           (desc ? strlen(desc) : 0) +
00326                                           (name ? strlen(name) : 0) +
00327                100;
00328   h = (char *) PR_MALLOC(hlen);
00329   if (!h) return MIME_OUT_OF_MEMORY;
00330 
00331   PL_strncpyz(h, HEADER_CONTENT_TYPE ": ", hlen);
00332   PL_strcatn(h, hlen, type);
00333   PL_strcatn(h, hlen, MSG_LINEBREAK);
00334   status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
00335   if (status < 0) goto FAIL;
00336 
00337   if (enc)
00338        {
00339          PL_strncpyz(h, HEADER_CONTENT_TRANSFER_ENCODING ": ", hlen);
00340          PL_strcatn(h, hlen, enc);
00341          PL_strcatn(h, hlen, MSG_LINEBREAK);
00342          status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
00343          if (status < 0) goto FAIL;
00344        }
00345 
00346   if (desc)
00347        {
00348          PL_strncpyz(h, HEADER_CONTENT_DESCRIPTION ": ", hlen);
00349          PL_strcatn(h, hlen, desc);
00350          PL_strcatn(h, hlen, MSG_LINEBREAK);
00351          status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
00352          if (status < 0) goto FAIL;
00353        }
00354   if (name)
00355        {
00356          PL_strncpyz(h, HEADER_CONTENT_DISPOSITION ": inline; filename=\"", hlen);
00357          PL_strcatn(h, hlen, name);
00358          PL_strcatn(h, hlen, "\"" MSG_LINEBREAK);
00359          status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
00360          if (status < 0) goto FAIL;
00361        }
00362 
00363   /* push out a blank line. */
00364   PL_strncpyz(h, MSG_LINEBREAK, hlen);
00365   status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs);
00366   if (status < 0) goto FAIL;
00367 
00368 
00369   /* Create a child... */
00370   {
00371        PRBool horrid_kludge = (obj->options && obj->options->state &&
00372                                                   obj->options->state->first_part_written_p);
00373        if (horrid_kludge)
00374          obj->options->state->first_part_written_p = PR_FALSE;
00375 
00376        uty->open_subpart = mime_create(type, uty->open_hdrs, obj->options);
00377 
00378        if (horrid_kludge)
00379          obj->options->state->first_part_written_p = PR_TRUE;
00380 
00381        if (!uty->open_subpart)
00382          {
00383               status = MIME_OUT_OF_MEMORY;
00384               goto FAIL;
00385          }
00386   }
00387 
00388   /* Add it to the list... */
00389   status = ((MimeContainerClass *) obj->clazz)->add_child(obj,
00390                                                                                                     uty->open_subpart);
00391   if (status < 0)
00392        {
00393          mime_free(uty->open_subpart);
00394          uty->open_subpart = 0;
00395          goto FAIL;
00396        }
00397 
00398   /* And start its parser going. */
00399   status = uty->open_subpart->clazz->parse_begin(uty->open_subpart);
00400   if (status < 0)
00401        {
00402          /* MimeContainer->finalize will take care of shutting it down now. */
00403          uty->open_subpart = 0;
00404          goto FAIL;
00405        }
00406 
00407   uty->type = ttype;
00408 
00409  FAIL:
00410   PR_FREEIF(h);
00411 
00412   if (status < 0 && uty->open_hdrs)
00413        {
00414          MimeHeaders_free(uty->open_hdrs);
00415          uty->open_hdrs = 0;
00416        }
00417 
00418   return status;
00419 }
00420 
00421 static PRBool
00422 MimeUntypedText_uu_begin_line_p(const char *line, PRInt32 length,
00423                                                         MimeDisplayOptions *opt,
00424                                                         char **type_ret, char **name_ret)
00425 {
00426   const char *s;
00427   char *name = 0;
00428   char *type = 0;
00429 
00430   if (type_ret) *type_ret = 0;
00431   if (name_ret) *name_ret = 0;
00432 
00433   if (strncmp (line, "begin ", 6)) return PR_FALSE;
00434   /* ...then three or four octal digits. */
00435   s = line + 6;
00436   if (*s < '0' || *s > '7') return PR_FALSE;
00437   s++;
00438   if (*s < '0' || *s > '7') return PR_FALSE;
00439   s++;
00440   if (*s < '0' || *s > '7') return PR_FALSE;
00441   s++;
00442   if (*s == ' ')
00443        s++;
00444   else
00445        {
00446          if (*s < '0' || *s > '7') return PR_FALSE;
00447          s++;
00448          if (*s != ' ') return PR_FALSE;
00449        }
00450 
00451   while (nsCRT::IsAsciiSpace(*s))
00452        s++;
00453 
00454   name = (char *) PR_MALLOC(((line+length)-s) + 1);
00455   if (!name) return PR_FALSE; /* grr... */
00456   memcpy(name, s, (line+length)-s);
00457   name[(line+length)-s] = 0;
00458 
00459   /* take off newline. */
00460   if (name[strlen(name)-1] == nsCRT::LF) name[strlen(name)-1] = 0;
00461   if (name[strlen(name)-1] == nsCRT::CR) name[strlen(name)-1] = 0;
00462 
00463   /* Now try and figure out a type.
00464    */
00465   if (opt && opt->file_type_fn)
00466        type = opt->file_type_fn(name, opt->stream_closure);
00467   else
00468        type = 0;
00469 
00470   if (name_ret)
00471        *name_ret = name;
00472   else
00473        PR_FREEIF(name);
00474 
00475   if (type_ret)
00476        *type_ret = type;
00477   else
00478        PR_FREEIF(type);
00479 
00480   return PR_TRUE;
00481 }
00482 
00483 static PRBool
00484 MimeUntypedText_uu_end_line_p(const char *line, PRInt32 length)
00485 {
00486 #if 0
00487   /* A strictly conforming uuencode end line. */
00488   return (line[0] == 'e' &&
00489                 line[1] == 'n' &&
00490                 line[2] == 'd' &&
00491                 (line[3] == 0 || nsCRT::IsAsciiSpace(line[3])));
00492 #else
00493   /* ...but, why don't we accept any line that begins with the three
00494         letters "END" in any case: I've seen lots of partial messages
00495         that look like
00496 
00497               BEGIN----- Cut Here-----
00498               begin 644 foo.gif
00499               Mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
00500               Mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
00501               Mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
00502               END------- Cut Here-----
00503 
00504         so let's be lenient here.  (This is only for the untyped-text-plain
00505         case -- the uudecode parser itself is strict.)
00506    */
00507   return (line[0] == ' ' ||
00508                 line[0] == '\t' ||
00509                 ((line[0] == 'e' || line[0] == 'E') &&
00510                  (line[1] == 'n' || line[1] == 'N') &&
00511                  (line[2] == 'd' || line[2] == 'D')));
00512 #endif
00513 }
00514 
00515 static PRBool
00516 MimeUntypedText_yenc_begin_line_p(const char *line, PRInt32 length,
00517                                                         MimeDisplayOptions *opt,
00518                                                         char **type_ret, char **name_ret)
00519 {
00520   const char *s;
00521   const char *endofline = line + length;
00522   char *name = 0;
00523   char *type = 0;
00524 
00525   if (type_ret) *type_ret = 0;
00526   if (name_ret) *name_ret = 0;
00527 
00528   /* we don't support yenc V2 neither multipart yencode,
00529      therefore the second parameter should always be "line="*/
00530   if (length < 13 || strncmp (line, "=ybegin line=", 13)) return PR_FALSE;
00531 
00532   /* ...then couple digits. */
00533   for (s = line + 13; s < endofline; s ++)
00534     if (*s < '0' || *s > '9')
00535       break;
00536 
00537   /* ...next, look for <space>size= */
00538   if ((endofline - s) < 6 || strncmp (s, " size=", 6)) return PR_FALSE;
00539   
00540   /* ...then couple digits. */
00541   for (s += 6; s < endofline; s ++)
00542     if (*s < '0' || *s > '9')
00543       break;
00544 
00545    /* ...next, look for <space>name= */
00546   if ((endofline - s) < 6 || strncmp (s, " name=", 6)) return PR_FALSE;
00547 
00548   /* anything left is the file name */
00549   s += 6;
00550   name = (char *) PR_MALLOC((endofline-s) + 1);
00551   if (!name) return PR_FALSE; /* grr... */
00552   memcpy(name, s, endofline-s);
00553   name[endofline-s] = 0;
00554 
00555   /* take off newline. */
00556   if (name[strlen(name)-1] == nsCRT::LF) name[strlen(name)-1] = 0;
00557   if (name[strlen(name)-1] == nsCRT::CR) name[strlen(name)-1] = 0;
00558 
00559   /* Now try and figure out a type.
00560    */
00561   if (opt && opt->file_type_fn)
00562        type = opt->file_type_fn(name, opt->stream_closure);
00563   else
00564        type = 0;
00565 
00566   if (name_ret)
00567        *name_ret = name;
00568   else
00569        PR_FREEIF(name);
00570 
00571   if (type_ret)
00572        *type_ret = type;
00573   else
00574        PR_FREEIF(type);
00575 
00576   return PR_TRUE;
00577 }
00578 
00579 static PRBool
00580 MimeUntypedText_yenc_end_line_p(const char *line, PRInt32 length)
00581 {
00582   if (length < 11 || strncmp (line, "=yend size=", 11)) return PR_FALSE;
00583 
00584   return PR_TRUE;    
00585 }
00586 
00587 
00588 #define BINHEX_MAGIC "(This file must be converted with BinHex 4.0)"
00589 #define BINHEX_MAGIC_LEN 45
00590 
00591 static PRBool
00592 MimeUntypedText_binhex_begin_line_p(const char *line, PRInt32 length,
00593                                                                MimeDisplayOptions *opt)
00594 {
00595   if (length <= BINHEX_MAGIC_LEN)
00596        return PR_FALSE;
00597 
00598   while(length > 0 && nsCRT::IsAsciiSpace(line[length-1]))
00599        length--;
00600 
00601   if (length != BINHEX_MAGIC_LEN)
00602        return PR_FALSE;
00603 
00604   if (!strncmp(line, BINHEX_MAGIC, BINHEX_MAGIC_LEN))
00605        return PR_TRUE;
00606   else
00607        return PR_FALSE;
00608 }
00609 
00610 static PRBool
00611 MimeUntypedText_binhex_end_line_p(const char *line, PRInt32 length)
00612 {
00613   if (length > 0 && line[length-1] == nsCRT::LF) length--;
00614   if (length > 0 && line[length-1] == nsCRT::CR) length--;
00615 
00616   if (length != 0 && length != 64)
00617        return PR_TRUE;
00618   else
00619        return PR_FALSE;
00620 }