Back to index

lightning-sunbird  0.9+nobinonly
nsClipboard.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.org 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) 1999-2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Stuart Parmenter <pavlov@netscape.com>
00025  *   Mike Pinkerton <pinkerton@netscape.com>
00026  *   Dan Rosen <dr@netscape.com>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsClipboard.h"
00043 
00044 #include <Pt.h>
00045 
00046 #include "nsCOMPtr.h"
00047 #include "nsCRT.h"
00048 #include "nsISupportsArray.h"
00049 #include "nsISupportsPrimitives.h"
00050 #include "nsReadableUtils.h"
00051 
00052 #include "nsIComponentManager.h"
00053 #include "nsIServiceManager.h"
00054 #include "nsWidgetsCID.h"
00055 #include "nsXPIDLString.h"
00056 #include "nsReadableUtils.h"
00057 #include "nsPrimitiveHelpers.h"
00058 
00059 #include "nsTextFormatter.h"
00060 
00061 #include "nsIServiceManager.h"
00062 #include "nsICharsetConverterManager.h"
00063 
00064 #include "prtime.h"
00065 #include "prthread.h"
00066 
00067 // unicode conversion
00068 #include "nsIPlatformCharset.h"
00069 #include "nsICharsetConverterManager.h"
00070 
00071 //#define DEBUG_CLIPBOARD
00072 
00073 
00074 // Define this to enable the obsolete X cut buffer mechanism
00075 // In general, a bad idea (see http://www.jwz.org/doc/x-cut-and-paste.html)
00076 // but it might have its uses for backwards compatibility.
00077 
00078 NS_IMPL_ISUPPORTS1(nsClipboard, nsIClipboard)
00079 
00080 #define Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK    "BOOK"
00081 #define Ph_CLIPBOARD_TYPE_IMAGE                  "IMAG"
00082 #define Ph_CLIPBOARD_TYPE_HTML                   "HTML"
00083 
00084 //-------------------------------------------------------------------------
00085 //
00086 // nsClipboard constructor
00087 //
00088 //-------------------------------------------------------------------------
00089 nsClipboard::nsClipboard()
00090 {
00091 #ifdef DEBUG_CLIPBOARD
00092   printf("nsClipboard::nsClipboard()\n");
00093 #endif /* DEBUG_CLIPBOARD */
00094 
00095   mIgnoreEmptyNotification = PR_FALSE;
00096   mGlobalTransferable = nsnull;
00097   mSelectionTransferable = nsnull;
00098   mGlobalOwner = nsnull;
00099   mSelectionOwner = nsnull;
00100   mInputGroup = 1;
00101 }
00102 
00103 //-------------------------------------------------------------------------
00104 //
00105 // nsClipboard destructor
00106 //
00107 //-------------------------------------------------------------------------
00108 nsClipboard::~nsClipboard()
00109 {
00110 #ifdef DEBUG_CLIPBOARD
00111   printf("nsClipboard::~nsClipboard()\n");  
00112 #endif /* DEBUG_CLIPBOARD */
00113 }
00114 
00119 NS_IMETHODIMP nsClipboard::SetData(nsITransferable * aTransferable,
00120                                    nsIClipboardOwner * anOwner,
00121                                    PRInt32 aWhichClipboard)
00122 {
00123        if (aWhichClipboard == kSelectionClipboard)
00124               return (NS_ERROR_FAILURE);
00125 
00126        if ((aTransferable == mGlobalTransferable.get() && anOwner == mGlobalOwner.get() && 
00127                      aWhichClipboard == kGlobalClipboard ) || (aTransferable == mSelectionTransferable.get() && 
00128                      anOwner == mSelectionOwner.get() && aWhichClipboard == kSelectionClipboard))
00129        {
00130               return NS_OK;
00131        }
00132 
00133        EmptyClipboard(aWhichClipboard);
00134 
00135        switch (aWhichClipboard) 
00136        {
00137               case kSelectionClipboard:
00138                      mSelectionOwner = anOwner;
00139                      mSelectionTransferable = aTransferable;
00140                      break;
00141               case kGlobalClipboard:
00142                      mGlobalOwner = anOwner;
00143                      mGlobalTransferable = aTransferable;
00144                      break;
00145        }
00146 
00147        return SetNativeClipboardData(aWhichClipboard);
00148 }
00149 
00154 NS_IMETHODIMP nsClipboard::GetData(nsITransferable * aTransferable, PRInt32 aWhichClipboard)
00155 {
00156        if (aWhichClipboard == kSelectionClipboard)
00157               return (NS_ERROR_FAILURE);
00158        if (nsnull != aTransferable)
00159               return GetNativeClipboardData(aTransferable, aWhichClipboard);
00160        else 
00161        {
00162 #ifdef DEBUG_CLIPBOARD
00163               printf("  nsClipboard::GetData(), aTransferable is NULL.\n");
00164 #endif
00165        }
00166 
00167        return NS_ERROR_FAILURE;
00168 }
00169 
00170 
00175 NS_IMETHODIMP nsClipboard::EmptyClipboard(PRInt32 aWhichClipboard)
00176 {
00177        if (mIgnoreEmptyNotification)
00178               return NS_OK;
00179 
00180        if (aWhichClipboard == kSelectionClipboard)
00181               return (NS_ERROR_FAILURE);
00182 
00183        switch(aWhichClipboard) 
00184        {
00185               case kSelectionClipboard:
00186                      return NS_ERROR_FAILURE;
00187                      if (mSelectionOwner) 
00188                      {
00189                             mSelectionOwner->LosingOwnership(mSelectionTransferable);
00190                             mSelectionOwner = nsnull;
00191                      }
00192                      mSelectionTransferable = nsnull;
00193                      break;
00194               case kGlobalClipboard:
00195                      if (mGlobalOwner) 
00196                      {
00197                             mGlobalOwner->LosingOwnership(mGlobalTransferable);
00198                             mGlobalOwner = nsnull;
00199                      }
00200                      mGlobalTransferable = nsnull;
00201                      break;
00202        }
00203 
00204        return NS_OK;
00205 }
00206 
00207 NS_IMETHODIMP nsClipboard::SupportsSelectionClipboard(PRBool *_retval)
00208 {
00209   NS_ENSURE_ARG_POINTER(_retval);
00210 
00211   *_retval = PR_FALSE; // we support the selection clipboard on unix.
00212   return NS_ERROR_FAILURE;
00213 }
00214 
00215 //-------------------------------------------------------------------------
00216 NS_IMETHODIMP nsClipboard::SetNativeClipboardData(PRInt32 aWhichClipboard)
00217 {
00218        mIgnoreEmptyNotification = PR_TRUE;
00219        if (aWhichClipboard == kSelectionClipboard)
00220               return (NS_ERROR_FAILURE);
00221 
00222 #ifdef DEBUG_CLIPBOARD
00223        printf("  nsClipboard::SetNativeClipboardData(%i)\n", aWhichClipboard);
00224 #endif /* DEBUG_CLIPBOARD */
00225 
00226               nsCOMPtr<nsITransferable> transferable(GetTransferable(aWhichClipboard));
00227 
00228        // make sure we have a good transferable
00229        if (nsnull == transferable) 
00230        {
00231 #ifdef DEBUG_CLIPBOARD
00232               printf("nsClipboard::SetNativeClipboardData(): no transferable!\n");
00233 #endif
00234               return NS_ERROR_FAILURE;
00235        }
00236 
00237        // get flavor list that includes all flavors that can be written (including ones 
00238        // obtained through conversion)
00239        nsCOMPtr<nsISupportsArray> flavorList;
00240        nsresult errCode = transferable->FlavorsTransferableCanExport ( getter_AddRefs(flavorList) );
00241        if ( NS_FAILED(errCode) )
00242               return NS_ERROR_FAILURE;
00243 
00244        PRUint32 cnt, index = 0;
00245        flavorList->Count(&cnt);
00246        PhClipHeader *cliphdr = (PhClipHeader *) calloc( cnt, sizeof( PhClipHeader ));
00247        if( !cliphdr ) return NS_ERROR_FAILURE;
00248 
00249        for ( PRUint32 k=0; k<cnt; ++k )
00250        {
00251               void      *data = nsnull;
00252               PRUint32   dataLen;
00253        
00254               nsCOMPtr<nsISupports> genericFlavor;
00255               flavorList->GetElementAt ( k, getter_AddRefs(genericFlavor) );
00256               nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
00257               if ( currentFlavor ) 
00258               {
00259                      nsXPIDLCString flavorStr;
00260                      currentFlavor->ToString(getter_Copies(flavorStr));
00261 
00262        nsresult err = GetFormat( flavorStr, cliphdr[index].type );
00263                      if( err != NS_OK ) 
00264                             continue;
00265 
00266                      // Get data out of transferable.
00267                      nsCOMPtr<nsISupports> genericDataWrapper;
00268                      transferable->GetTransferData( flavorStr, getter_AddRefs(genericDataWrapper), &dataLen );
00269                      nsPrimitiveHelpers::CreateDataFromPrimitive ( flavorStr, genericDataWrapper, &data, dataLen );
00270 
00271                      if( !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_TEXT) ||
00272                                    !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_HTML) ||
00273                                    !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK) )
00274                      {
00275                             PRUnichar* castedUnicode = NS_REINTERPRET_CAST(PRUnichar*, data);
00276                             char *utf8String = ToNewUTF8String(nsDependentString(castedUnicode, dataLen/2));
00277                             nsMemory::Free(NS_REINTERPRET_CAST(char*, data));
00278 
00279                             if( !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_TEXT) )
00280                             {
00281                                    /* we have to create a null terminated string, because
00282                                           PhClipboardCopyString does that and some other applications
00283                                           rely on the null terminated thing
00284                                    */
00285                                    PRInt32 len = strlen(utf8String);
00286                                    char *temp = ( char * ) nsMemory::Alloc( len + 1 );
00287                                    memcpy( temp, utf8String, len );
00288                                    temp[len] = 0;
00289                                    nsMemory::Free(NS_REINTERPRET_CAST(char*, utf8String));
00290 
00291               cliphdr[index].length = len+1;
00292               cliphdr[index].data = temp;
00293                             }
00294                      else {
00295                             cliphdr[index].length = strlen(utf8String);
00296                             cliphdr[index].data = utf8String;
00297                             }
00298                      }
00299        index++;      
00300               }
00301        }
00302 
00303        PhClipboardCopy( mInputGroup, index, cliphdr );
00304        for( PRUint32 k=0; k<index; k++)
00305               nsMemory::Free(NS_REINTERPRET_CAST(char*, cliphdr[k].data));
00306 
00307        free( cliphdr );
00308 
00309        mIgnoreEmptyNotification = PR_FALSE;
00310 
00311        return NS_OK;
00312 }
00313 
00314 
00315 //-------------------------------------------------------------------------
00316 //
00317 // The blocking Paste routine
00318 //
00319 //-------------------------------------------------------------------------
00320 NS_IMETHODIMP
00321 nsClipboard::GetNativeClipboardData(nsITransferable * aTransferable, 
00322                                     PRInt32 aWhichClipboard)
00323 {
00324        if (aWhichClipboard == kSelectionClipboard)
00325               return (NS_ERROR_FAILURE);
00326 
00327 #ifdef DEBUG_CLIPBOARD
00328        printf("nsClipboard::GetNativeClipboardData(%i)\n", aWhichClipboard);
00329 #endif /* DEBUG_CLIPBOARD */
00330 
00331        // make sure we have a good transferable
00332        if (nsnull == aTransferable) 
00333        {
00334 #ifdef DEBUG_CLIPBOARD
00335     printf("  GetNativeClipboardData: Transferable is null!\n");
00336 #endif
00337        return NS_ERROR_FAILURE;
00338        }
00339 
00340        // get flavor list that includes all acceptable flavors (including ones obtained through
00341        // conversion)
00342        nsCOMPtr<nsISupportsArray> flavorList;
00343        nsresult errCode = aTransferable->FlavorsTransferableCanImport ( getter_AddRefs(flavorList) );
00344        if ( NS_FAILED(errCode) )
00345               return NS_ERROR_FAILURE;
00346 
00347        // Walk through flavors and see which flavor matches the one being pasted:
00348        PRUint32 cnt;
00349        flavorList->Count(&cnt);
00350        nsCAutoString foundFlavor;
00351 
00352        if (cnt > 0) 
00353        {
00354        void         *clipPtr;
00355        PhClipHeader *cliphdr;
00356        char         *data = nsnull, type[8];
00357        PRUint32      dataLen;
00358 
00359        clipPtr = PhClipboardPasteStart( mInputGroup );
00360        if(!clipPtr) return NS_ERROR_FAILURE;
00361 
00362        /*
00363               Look at the timestamps of the data in the clipboard and eliminate the flavours if they are not synchronized.
00364               We can have a HTML flavour from a previous copy and a TEXT flavour from a more recent copy from another application
00365               ( from instance from ped or pterm ). The HTML flavour and TEXT flavour are desynchronized and we have
00366               to use only the most recent one */
00367               unsigned long *dont_use_flavour = ( unsigned long * ) calloc( cnt, sizeof( unsigned long ) );
00368               if( !dont_use_flavour ) {
00369                      PhClipboardPasteFinish( clipPtr );
00370                      return NS_ERROR_FAILURE;
00371                      }
00372 
00373               unsigned long max_time = 0;
00374               PRUint32 i;
00375 
00376               for ( i = 0; i < cnt; ++i ) 
00377               {
00378                      nsCOMPtr<nsISupports> genericFlavor;
00379                      flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
00380                      nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
00381                      if ( currentFlavor ) 
00382                      {
00383                             nsXPIDLCString flavorStr;
00384                             currentFlavor->ToString ( getter_Copies(flavorStr) );
00385 
00386                             nsresult err = GetFormat( flavorStr, type );
00387                             if (err != NS_OK) 
00388                                    continue;
00389 
00390                      dont_use_flavour[i] = GetFlavourTimestamp( type );
00391                      if( dont_use_flavour[i] > max_time ) max_time = dont_use_flavour[i];
00392                      }
00393               }
00394 
00395               for ( i = 0; i < cnt; ++i )
00396               {
00397               if( abs( dont_use_flavour[i] - max_time ) >= 4 )
00398                      dont_use_flavour[i] = 1; /* this flavour is desynchronized */
00399               else dont_use_flavour[i] = 0; /* this flavour is ok */
00400               }
00401 
00402               for ( i = 0; i < cnt; ++i ) 
00403               {
00404                      if( dont_use_flavour[i] ) continue; /* this flavour is desynchronized */
00405                      nsCOMPtr<nsISupports> genericFlavor;
00406                      flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
00407                      nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
00408                      if ( currentFlavor ) 
00409                      {
00410                             nsXPIDLCString flavorStr;
00411                             currentFlavor->ToString ( getter_Copies(flavorStr) );
00412 
00413                             nsresult err = GetFormat( flavorStr, type );
00414                             if (err != NS_OK) 
00415                                    continue;
00416 
00417                             cliphdr = PhClipboardPasteType( clipPtr, type );
00418                             if (cliphdr) 
00419                             {
00420                                    data = (char*)cliphdr->data;
00421 
00422                                    if( !strcmp(type, Ph_CLIPBOARD_TYPE_TEXT) )
00423                                           /* for the Ph_CLIPBOARD_TYPE_TEXT, we null terminate the data, since PhClipboardCopyString() does that */
00424                                           dataLen = cliphdr->length - 1;
00425                                    else dataLen = cliphdr->length;
00426 
00427 
00428                                    if( !strcmp(type, Ph_CLIPBOARD_TYPE_TEXT) ||
00429                                                  !strcmp(type, Ph_CLIPBOARD_TYPE_HTML) ||
00430                                                  !strcmp(type, Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK) )
00431                                    {
00432                                           nsresult rv;
00433                                           PRInt32 outUnicodeLen;
00434                                           PRUnichar *unicodeData = nsnull;
00435 
00436                             // get the decoder
00437                             nsCOMPtr<nsIUnicodeDecoder> decoder;
00438                             nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
00439                             rv = ccm->GetUnicodeDecoderRaw("UTF-8", getter_AddRefs(decoder));
00440 
00441                             if( NS_SUCCEEDED(rv) )
00442                                                  {
00443 
00444                                    decoder->GetMaxLength(data, dataLen, &outUnicodeLen);   // |outUnicodeLen| is number of chars
00445                                    if (outUnicodeLen) {
00446                                    unicodeData = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc((outUnicodeLen + 1) * sizeof(PRUnichar)));
00447                                    if ( unicodeData ) {
00448                                           PRInt32 numberTmp = dataLen;
00449                                           rv = decoder->Convert(data, &numberTmp, unicodeData, &outUnicodeLen);
00450 #ifdef DEBUG_CLIPBOARD
00451                                           if (numberTmp != dataLen)
00452                                             printf("didn't consume all the bytes\n");
00453 #endif
00454 
00455                                           (unicodeData)[outUnicodeLen] = '\0';    // null terminate. Convert() doesn't do it for us
00456                                           }
00457                                                         } // if valid length
00458 
00459 
00460                                    data = NS_REINTERPRET_CAST(char*,unicodeData);
00461                                    dataLen = outUnicodeLen * 2;
00462 
00463                                                  nsCOMPtr<nsISupports> genericDataWrapper;
00464                                                  nsPrimitiveHelpers::CreatePrimitiveForData( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) );
00465                                                  aTransferable->SetTransferData( flavorStr, genericDataWrapper, dataLen );
00466 
00467                                                  /* free the allocated memory */
00468                                                  nsMemory::Free( unicodeData );
00469 
00470                                    break;
00471                                                  }
00472                                    }
00473               }
00474                      }
00475               }
00476 
00477               free( dont_use_flavour );
00478               PhClipboardPasteFinish( clipPtr );
00479        }
00480 
00481        return NS_OK;
00482 }
00483 
00484 NS_IMETHODIMP
00485 nsClipboard::HasDataMatchingFlavors(nsISupportsArray* aFlavorList, 
00486                                     PRInt32 aWhichClipboard, 
00487                                     PRBool * outResult)
00488 {
00489        if (aWhichClipboard == kSelectionClipboard)
00490               return (NS_ERROR_FAILURE);
00491   // XXX this doesn't work right.  need to fix it.
00492   
00493   // Note to implementor...(from pink the clipboard bitch).
00494   //
00495   // If a client asks for unicode, first check if unicode is present. If not, then 
00496   // check for plain text. If it's there, say "yes" as we will do the conversion
00497   // in GetNativeClipboardData(). From this point on, no client will
00498   // ever ask for text/plain explicitly. If they do, you must ASSERT!
00499 #ifdef DEBUG_CLIPBOARD
00500        printf("  nsClipboard::HasDataMatchingFlavors()\n  {\n");
00501 #endif
00502 
00503   nsresult res = NS_OK;
00504   * outResult = PR_FALSE;
00505 
00506  // Walk through flavors and see which flavor matches the one being pasted:
00507   PRUint32 cnt;
00508 
00509   aFlavorList->Count(&cnt);
00510   nsCAutoString foundFlavor;
00511   if (cnt > 0) {
00512     void         *clipPtr;
00513               char                               type[8];
00514     PhClipHeader *cliphdr;
00515 
00516     clipPtr = PhClipboardPasteStart( 1 );
00517     if(nsnull == clipPtr)
00518         return res;
00519 
00520     for ( PRUint32 i = 0; i < cnt; ++i ) {
00521       nsCOMPtr<nsISupports> genericFlavor;
00522       aFlavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
00523       nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
00524 
00525       if ( currentFlavor ) {
00526 
00527         nsXPIDLCString flavorStr;
00528         currentFlavor->ToString ( getter_Copies(flavorStr) );
00529 
00530         nsresult err = GetFormat( flavorStr, type );
00531         if (err != NS_OK) continue;
00532 
00533         cliphdr = PhClipboardPasteType( clipPtr, type );
00534         if (cliphdr)
00535         {
00536 
00537             res = NS_OK;
00538             *outResult = PR_TRUE;
00539                     break;
00540         }
00541       }
00542     }
00543 
00544     PhClipboardPasteFinish( clipPtr );
00545   }
00546 
00547   return res;
00548 }
00549 
00550 
00551 nsresult nsClipboard::GetFormat(const char* aMimeStr, char *format ) 
00552 {
00553        nsDependentCString mimeStr(aMimeStr);
00554        int ret = NS_OK;
00555 
00556        if( mimeStr.Equals(kUnicodeMime) || mimeStr.Equals(kTextMime) )
00557        strcpy( format, Ph_CLIPBOARD_TYPE_TEXT );
00558        else if( mimeStr.Equals(kHTMLMime) )
00559        strcpy( format, Ph_CLIPBOARD_TYPE_HTML );
00560        else if (mimeStr.Equals("moz/bookmarkclipboarditem"))
00561        strcpy( format, Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK );
00562        else ret = NS_ERROR_FAILURE;
00563        return ret;
00564 }
00565 
00566 /* inline */
00567 nsITransferable *nsClipboard::GetTransferable(PRInt32 aWhichClipboard)
00568 {
00569   nsITransferable *transferable = nsnull;
00570   switch (aWhichClipboard)
00571   {
00572   case kGlobalClipboard:
00573     transferable = mGlobalTransferable;
00574     break;
00575   case kSelectionClipboard:
00576     break;
00577   }
00578   return transferable;
00579 }
00580 
00581 unsigned long nsClipboard::GetFlavourTimestamp( char *type)
00582 {
00583        char fname[512];
00584        extern struct _Ph_ctrl *_Ph_;
00585 
00586   strcpy( fname, "/var/clipboard/" );
00587   if( access( fname, X_OK ) != 0 )
00588               return 0;
00589 
00590        struct stat buf;
00591        if( fstat( _Ph_->fd, &buf ) != 0 )
00592               return 0;
00593 
00594   if(gethostname(&fname[strlen(fname)],PATH_MAX-40)!=0)
00595     strcpy(&fname[strlen(fname)],"localhost");
00596 
00597   sprintf( &fname[strlen(fname)], "/%08x/%d.%s",buf.st_uid, mInputGroup, type );
00598        struct stat st;
00599        if( stat( fname, &st ) != 0 )
00600               return 0;
00601 
00602        return st.st_mtime;
00603 }