/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ // Implementation of file-based ITapeFileSystem. // Used by the editor to save to disk. #ifdef EDITOR // Work-around for Win16 precompiled header bug -- all .cpp files in // lib/layout have to include editor.h first. This file // doesn't even need editor.h. ////// Now it does, edt_StripUsernamePassword. #include "editor.h" #include "fsfile.h" #ifdef XP_MAC #include "xp_file_mac.h" #endif //----------------------------------------------------------------------------- // CFileBackup // // File backup and restore Object, only used by CTapeFSFile. // //----------------------------------------------------------------------------- class CFileBackup { private: XP_Bool m_bInitOk; char *m_pBackupName; char *m_pFileName; public: CFileBackup(): m_bInitOk(FALSE), m_pBackupName(0), m_pFileName(0){} ~CFileBackup(){ Reset(); } void Reset(); XP_Bool InTransaction(){ return m_bInitOk; } ED_FileError BeginTransaction( char *pDestURL ); char* FileName(){ return m_pFileName; } void Commit(); void Rollback(); }; void CFileBackup::Reset(){ if( m_pBackupName ){ XP_FREE( m_pBackupName ); m_pBackupName = 0; } if( m_pFileName ){ XP_FREE( m_pFileName ); m_pFileName = 0; } m_bInitOk = FALSE; } ED_FileError CFileBackup::BeginTransaction( char *pDestURL ){ XP_StatStruct statinfo; if ( pDestURL == NULL || XP_STRLEN(pDestURL) == 0 || !NET_IsLocalFileURL(pDestURL) ) { return ED_ERROR_BAD_URL; } // Skip past the "file://" in pDestURL m_pFileName = NET_ParseURL(pDestURL,GET_PATH_PART); if (!m_pFileName) { return ED_ERROR_CREATE_BAKNAME; } if (XP_Stat(m_pFileName, &statinfo, xpURL) != -1) { if ( XP_STAT_READONLY( statinfo ) ){ return ED_ERROR_READ_ONLY; } // File exists - rename to backup to protect data m_pBackupName = XP_BackupFileName(pDestURL); if ( m_pBackupName == NULL ) { return ED_ERROR_CREATE_BAKNAME; } // Delete backup file if it exists if ( -1 != XP_Stat(m_pBackupName, &statinfo, xpURL) && statinfo.st_mode & S_IFREG ) { if ( 0 != XP_FileRemove(m_pBackupName, xpURL) ) { return ED_ERROR_DELETE_BAKFILE; } } if ( 0 != XP_FileRename(m_pFileName, xpURL, m_pBackupName, xpURL) ){ return ED_ERROR_FILE_RENAME_TO_BAK; } } // else file doesn't already exist, so no worries. m_bInitOk = TRUE; return ED_ERROR_NONE; } void CFileBackup::Commit() { XP_ASSERT( m_bInitOk ); #ifdef XP_UNIX XP_StatStruct statinfo; if (m_pBackupName != NULL && m_pFileName != NULL && XP_Stat(m_pBackupName, &statinfo, xpURL) != -1) { /* * Is there an XP_chmod()? I cannot find one. This will * work for Unix, which is probably the only place that cares. * Don't bother to check the return status, as it's too late to * do anything about, and we are not in dire straights if it fails. * Bug #28775..djw */ chmod(m_pFileName, statinfo.st_mode); } #endif #ifdef XP_MAC // Mac needs to duplicate the resource fork of the old file into new location // when there is a save or saveas; this preserves CKID rsrc among other things if ( m_pBackupName != NULL && m_pFileName != NULL ) int result = XP_FileDuplicateResourceFork( m_pBackupName, xpURL, m_pFileName, xpURL ); #endif XP_FileRemove(m_pBackupName, xpURL); } void CFileBackup::Rollback(){ XP_ASSERT( m_bInitOk ); if ( m_pBackupName ) { // Restore previous file // If this fails, we're really messed up! XP_FileRemove(m_pFileName, xpURL); XP_FileRename(m_pBackupName, xpURL, m_pFileName, xpURL); } } //------------------------------------------------------------------------------- // CTapeFSFile: File-based version of abstract file system //------------------------------------------------------------------------------- CTapeFSFile::CTapeFSFile(char *pDestPathURL,char *pDestURL): m_pSrcBaseURL(0) { XP_ASSERT(pDestPathURL && pDestURL); m_pDestPathURL = XP_STRDUP(pDestPathURL); m_pDestURL = XP_STRDUP(pDestURL); XP_ASSERT(m_pDestPathURL && m_pDestURL); } CTapeFSFile::~CTapeFSFile() { ///// TODO DELETE TEMP FILES int i; for (i = 0; i < m_srcURLs.Size(); i++) { if (m_srcURLs[i]) XP_FREE(m_srcURLs[i]); } for (i = 0; i < m_destFilenames.Size(); i++) { if (m_destFilenames[i]) XP_FREE(m_destFilenames[i]); } for (i = 0; i < m_streamOuts.Size(); i++) { if (m_streamOuts[i]) // really don't need to check for NULL with C++ delete delete m_streamOuts[i]; } for (i = 0; i < m_fileBackups.Size(); i++) { if (m_fileBackups[i]) // really don't need to check for NULL with C++ delete delete m_fileBackups[i]; } if (m_pDestPathURL) XP_FREE(m_pDestPathURL); if (m_pDestURL) XP_FREE(m_pDestURL); if (m_pSrcBaseURL) XP_FREE(m_pSrcBaseURL); } void CTapeFSFile::CopyURLInfo(intn, const URL_Struct *) { } intn CTapeFSFile::GetType() { return ITapeFileSystem::File; } void CTapeFSFile::SetSourceBaseURL(char *pURL){ // Shouldn't pass in NULL, and m_pSrcBaseURL shouldn't already exist. if (m_pSrcBaseURL || !pURL) { XP_ASSERT(0); return; } m_pSrcBaseURL = XP_STRDUP(pURL); } intn CTapeFSFile::AddFile(char *pURL, char *, int16) { // MIME type and char set are ignored. // Make pSrcURL absolute if SetSourceBaseURL() was called. char *pSrcURL; if (m_pSrcBaseURL) pSrcURL = NET_MakeAbsoluteURL(m_pSrcBaseURL,pURL); else pSrcURL = XP_STRDUP(pURL); if (!pSrcURL) return ITapeFileSystem::Error; // First file added is the root HTML document, it's destination filename was passed in to // the constructor of CTapeFSFile. XP_Bool use_m_pDestURL = (m_srcURLs.Size() == 0); // Compute and store relative destination filename. char *pDestFilename; if (use_m_pDestURL) { // Kind of redundant, here we are stripping the path, only to put it back on in CTapeFSFile::OpenStream(). pDestFilename = FE_URLToLocalName(m_pDestURL); } else { pDestFilename = FE_URLToLocalName(pSrcURL); } if (!pDestFilename) { XP_FREE(pSrcURL); return ITapeFileSystem::Error; } // Check if source and destination are the same. // It's ok for the root HTML document to have the same source and dest. // // pSrcURL is absolute if (!use_m_pDestURL && EDT_IsSameURL(pSrcURL,pDestFilename,NULL,m_pDestURL)) { XP_FREE(pSrcURL); XP_FREE(pDestFilename); return ITapeFileSystem::SourceDestSame; } // See if pSrcURL is already in the list. int i = 0; while( i < m_srcURLs.Size() ){ if( EDT_IsSameURL( pSrcURL, m_srcURLs[i], NULL, NULL ) ){ XP_FREE(pSrcURL); XP_FREE(pDestFilename); return i; } i++; } // Add to lists. int ret = m_srcURLs.Add(pSrcURL); m_destFilenames.Add(pDestFilename); // Keep m_streamOuts and m_fileBackups the same size as the others. m_streamOuts.Add(NULL); m_fileBackups.Add(NULL); return ret; } char* CTapeFSFile::GetSourceURL(intn iFileIndex) { if (iFileIndex >= 0 && iFileIndex < m_srcURLs.Size()) { return XP_STRDUP(m_srcURLs[iFileIndex]); } else { XP_ASSERT(0); return NULL; } } char* CTapeFSFile::GetDestAbsURL() { return XP_STRDUP(m_pDestURL); } char *CTapeFSFile::GetDestURL(intn iFileIndex) { if (iFileIndex >= 0 && iFileIndex < m_destFilenames.Size()) { return XP_STRDUP(m_destFilenames[iFileIndex]); } else { XP_ASSERT(0); return NULL; } } char *CTapeFSFile::GetDestPathURL() { return XP_STRDUP(m_pDestPathURL); } XP_Bool CTapeFSFile::IsLocalPersistentFile(intn) { return TRUE; } XP_Bool CTapeFSFile::FileExists(intn iFileIndex) { // Check iFileIndex if (iFileIndex < 0 || iFileIndex >= m_destFilenames.Size()) { XP_ASSERT(0); return FALSE; } char *pLocalName = PR_smprintf( "%s%s", m_pDestPathURL, m_destFilenames[iFileIndex]); if (!pLocalName) { XP_ASSERT(0); return FALSE; } // Get everything after "file://" char *pxpURL = NET_ParseURL(pLocalName,GET_PATH_PART); XP_FREE(pLocalName); if (!pxpURL) { XP_ASSERT(0); return FALSE; } XP_StatStruct statinfo; Bool result = ( -1 != XP_Stat(pxpURL, &statinfo, xpURL) && statinfo.st_mode & S_IFREG ); XP_FREE(pxpURL); return result; } IStreamOut * CTapeFSFile::OpenStream( intn iFileIndex ) { // Check iFileIndex if (iFileIndex < 0 || iFileIndex >= m_destFilenames.Size()) { XP_ASSERT(0); return NULL; } // Create fileBackup object XP_ASSERT( m_fileBackups[iFileIndex] == NULL ); // Shouldn't already exist. m_fileBackups[iFileIndex]= new CFileBackup; m_fileBackups[iFileIndex]->Reset(); char *pDestURL = PR_smprintf( "%s%s", m_pDestPathURL, m_destFilenames[iFileIndex]); if ( !pDestURL ) { XP_ASSERT(0); return NULL; } ED_FileError status = m_fileBackups[iFileIndex]->BeginTransaction( pDestURL ); if( status != ED_ERROR_NONE ){ XP_FREE(pDestURL); return NULL; } // Get path part of URL, e.g. without file://, for everything that uses xpURL char *pDestPath = NET_ParseURL(pDestURL,GET_PATH_PART); XP_FREE(pDestURL); if (!pDestPath) { XP_ASSERT(0); return NULL; } XP_File outFile = 0; // First file is text, rest are binary. // Right, well now the first file may be text or binary. This is still // bogus-- each file should have a flag telling it's time, but I don't // have time to redesign the #!$#@!#!@$ editor. XP_FilePerm filePerm = ((iFileIndex == 0) && (!IsFirstBinary())) ? XP_FILE_TRUNCATE : XP_FILE_TRUNCATE_BIN; outFile = XP_FileOpen(pDestPath, xpURL, filePerm ); XP_FREE(pDestPath); if( outFile == 0 ){ return NULL; } // Now open a stream to outFile. // // First file is text, rest are binary. CStreamOutFile *streamOut = new CStreamOutFile(outFile,iFileIndex == 0 ? FALSE : TRUE); XP_ASSERT(streamOut); XP_ASSERT(m_streamOuts[iFileIndex] == NULL); // not already set // Store stream for later. m_streamOuts[iFileIndex] = streamOut; return streamOut; } void CTapeFSFile::CloseStream( intn iFileIndex ) { if (iFileIndex < 0 || iFileIndex >= m_streamOuts.Size() || !m_streamOuts[iFileIndex]) { XP_ASSERT(0); return; } delete m_streamOuts[iFileIndex]; m_streamOuts[iFileIndex] = NULL; } void CTapeFSFile::Complete( XP_Bool bSuccess, EDT_ITapeFileSystemComplete *pfComplete, void *pArg ) { // Commit or rollback all file changes, depending on the value of bSuccess. int i; for ( i = 0; i < m_fileBackups.Size(); i++ ) { if ( !m_fileBackups[i] ) { continue; } if ( m_fileBackups[i]->InTransaction() ) { if ( bSuccess ) m_fileBackups[i]->Commit(); else m_fileBackups[i]->Rollback(); } } if (pfComplete) { pfComplete(TRUE,pArg); } delete this; } //------------------------------------------------------------------------------- // CTapeFSPublish: Remote HTTP publish version of abstract file system //------------------------------------------------------------------------------- CTapeFSPublish::CTapeFSPublish(MWContext *pMWContext, char *pRemoteURL, char *pUsername, char *pPassword, char *pTempDir) : m_iVerifier(iVerifierKey), m_pSrcBaseURL(NULL), m_pRemoteURL(XP_STRDUP(pRemoteURL)), m_pUsername(pUsername ? XP_STRDUP(pUsername) : 0), m_pPassword(pPassword ? XP_STRDUP(pPassword) : 0), m_pArg(0), m_pfComplete(0), m_bIsHTTP(FALSE), m_pTempDir(XP_STRDUP(pTempDir)) { m_pMWContext = pMWContext; XP_ASSERT( m_pRemoteURL && pMWContext ); // m_pTempDir must end in a slash. XP_ASSERT(m_pTempDir && *m_pTempDir && m_pTempDir[XP_STRLEN(m_pTempDir)-1] == '/'); int type = NET_URL_Type(pRemoteURL); if (type == FTP_TYPE_URL) { m_bIsHTTP = FALSE; } else if (type == HTTP_TYPE_URL || type == SECURE_HTTP_TYPE_URL) { m_bIsHTTP = TRUE; } else { XP_ASSERT(0); } } CTapeFSPublish::~CTapeFSPublish() { XP_FREEIF(m_pSrcBaseURL); int i; for (i = 0; i < m_srcURLs.Size(); i++) { XP_FREEIF(m_srcURLs[i]); } XP_FREEIF(m_pRemoteURL); XP_FREEIF(m_pUsername); XP_FREEIF(m_pPassword); for (i = 0; i < m_remoteURLs.Size(); i++) { XP_FREEIF(m_remoteURLs[i]); } XP_FREEIF(m_pTempDir); for (i = 0; i < m_tempFilenames.Size(); i++) { if (m_tempFilenames[i]) { // Delete temp files. XP_FileRemove(m_tempFilenames[i], xpFileToPost); XP_FREE(m_tempFilenames[i]); } } for (i = 0; i < m_streamOuts.Size(); i++) { if (m_streamOuts[i]) // really don't need to check for NULL with C++ delete delete m_streamOuts[i]; } } void CTapeFSPublish::CopyURLInfo(intn, const URL_Struct *) { } intn CTapeFSPublish::GetType() { return ITapeFileSystem::Publish; } // Some random value. int32 CTapeFSPublish::iVerifierKey = 0xABACADAE; void CTapeFSPublish::SetSourceBaseURL(char *pURL){ // Shouldn't pass in NULL, and m_pSrcBaseURL shouldn't already exist. if (m_pSrcBaseURL || !pURL) { XP_ASSERT(0); return; } m_pSrcBaseURL = XP_STRDUP(pURL); } intn CTapeFSPublish::AddFile(char *pURL, char *, int16) { // MIME type and char set are ignored. // Make pSrcURL absolute if SetSourceBaseURL() was called. char *pSrcURL; if (m_pSrcBaseURL) pSrcURL = NET_MakeAbsoluteURL(m_pSrcBaseURL,pURL); else pSrcURL = XP_STRDUP(pURL); if (!pSrcURL) return ITapeFileSystem::Error; // See if pSrcURL is already in the list. int i = 0; while( i < m_srcURLs.Size() ){ if( EDT_IsSameURL( pSrcURL, m_srcURLs[i], NULL, NULL)){ XP_FREE(pSrcURL); return i; } i++; } // Note that the way pNewRemoteURL is constructed has the desirable // side effect of NOT copying in any username/password information // in pURL. char *pNewRemoteURL = NULL; if (m_srcURLs.Size() == 0) // First file added is the root HTML document. pNewRemoteURL = XP_STRDUP(m_pRemoteURL); else { // All others are images that will be placed in the directory of the root doc. pNewRemoteURL = makeLocal(m_pRemoteURL,pSrcURL); } if ( !pNewRemoteURL ) { XP_FREE(pSrcURL); return ITapeFileSystem::Error; } // Check if would be copying from one location to itself. if (m_srcURLs.Size() > 0 && // Make sure not the root document. EDT_IsSameURL(pSrcURL,pNewRemoteURL,NULL,m_pRemoteURL)) { XP_FREE(pSrcURL); XP_FREE(pNewRemoteURL); return ITapeFileSystem::SourceDestSame; } // Add to lists. int ret = m_srcURLs.Add(pSrcURL); m_remoteURLs.Add(pNewRemoteURL); // Keep the same size as the other arrays.. m_tempFilenames.Add(NULL); m_streamOuts.Add(NULL); return ret; } char* CTapeFSPublish::GetSourceURL(intn iFileIndex) { if (iFileIndex >= 0 && iFileIndex < m_srcURLs.Size()) { return XP_STRDUP(m_srcURLs[iFileIndex]); } else { XP_ASSERT(0); return NULL; } } char* CTapeFSPublish::GetDestAbsURL() { return XP_STRDUP(m_pRemoteURL); } char *CTapeFSPublish::GetUsername() { return m_pUsername ? XP_STRDUP(m_pUsername) : 0; } char *CTapeFSPublish::GetPassword() { return m_pPassword ? XP_STRDUP(m_pPassword) : 0; } char *CTapeFSPublish::GetDestURL(intn iFileIndex) { if (iFileIndex >= 0 && iFileIndex < m_remoteURLs.Size()) { // Find last slash. char *slash = XP_STRRCHR(m_remoteURLs[iFileIndex],'/'); if (!slash) { XP_ASSERT(0); return NULL; } // Copy everything after the slash. return XP_STRDUP(slash + 1); } else { XP_ASSERT(0); return NULL; } } char *CTapeFSPublish::GetDestPathURL() { // Grab everything before and including the last slash in m_pRemoteURL. char *slash = XP_STRRCHR(m_pRemoteURL,'/'); if (!slash) { XP_ASSERT(0); return NULL; } char tmp = *(slash + 1); *(slash + 1) = '\0'; char *ret = XP_STRDUP(m_pRemoteURL); *(slash + 1) = tmp; return ret; } XP_Bool CTapeFSPublish::IsLocalPersistentFile(intn /* iFileIndex */) { return FALSE; } IStreamOut * CTapeFSPublish::OpenStream( intn iFileIndex ) { // Check iFileIndex if (iFileIndex < 0 || iFileIndex >= m_tempFilenames.Size()) { XP_ASSERT(0); return NULL; } // WARNING: We are pulling a fast one here, m_pTempDir is xpURL and we treat it as xpFileToPost. // Since there are no routines to convert a filename to xpFileToPost, I just take advantage of // it being the same as xpURL. // Get filename of temporary file. // Use the temporary file of the current document. // Start filename with "pub" so it doesn't collide with CEditCommandLog::CreateDocTempFilename() // which starts all filenames with "edt" by default. char *pTempFilename = PR_smprintf("%spubl%d.tmp",m_pTempDir,(int)iFileIndex); // m_pTempDir ends in slash. if (!pTempFilename) { return NULL; } m_tempFilenames[iFileIndex] = pTempFilename; XP_File outFile = 0; // First file is text, rest are binary. // Right, well now the first file may be text or binary. This is still // bogus-- each file should have a flag telling it's time, but I don't // have time to redesign the #!$#@!#!@$ editor. XP_FilePerm filePerm = ((iFileIndex == 0) && (!IsFirstBinary())) ? XP_FILE_TRUNCATE : XP_FILE_TRUNCATE_BIN; outFile = XP_FileOpen(m_tempFilenames[iFileIndex], xpFileToPost, filePerm ); XP_TRACE(("XP_FileOpen handle = %d", outFile)); if( outFile == 0 ){ XP_TRACE(("Failed to opened file %s", m_tempFilenames[iFileIndex])); // Delete and clear temp filename, this serves as a flag to // Complete() that this entry should not be published. XP_FREEIF(m_tempFilenames[iFileIndex]); return NULL; } // Now open a stream to outFile. // // First file is text, rest are binary. CStreamOutFile *streamOut = new CStreamOutFile(outFile,iFileIndex == 0 ? FALSE : TRUE); if (!streamOut) { // Out of memory. XP_ASSERT(0); return NULL; } XP_ASSERT(m_streamOuts[iFileIndex] == NULL); // not already set // Store stream for later. m_streamOuts[iFileIndex] = streamOut; return streamOut; } void CTapeFSPublish::CloseStream( intn iFileIndex ) { if (iFileIndex < 0 || iFileIndex >= m_streamOuts.Size() || !m_streamOuts[iFileIndex]) { XP_ASSERT(0); return; } if (m_streamOuts[iFileIndex]->Status() != IStreamOut::EOS_NoError) { // Delete and clear temp filename, this serves as a flag to // Complete() that this entry should not be published. XP_FREEIF(m_tempFilenames[iFileIndex]); } delete m_streamOuts[iFileIndex]; m_streamOuts[iFileIndex] = NULL; } #if defined(XP_OS2) extern "C" #else PRIVATE #endif void edt_CTapeFSExit( URL_Struct *pURL, int status, MWContext * ) { CTapeFSPublish *tapeFS = (CTapeFSPublish *)pURL->fe_data; // Make sure that fe_data can be trusted. if (!(tapeFS && tapeFS->Verify())) { XP_ASSERT(0); return; } // Call complete function passed into CTapeFSPublish::Complete(). if (tapeFS->m_pfComplete) { XP_Bool bSuccess = (status >= 0 && (pURL->server_status == 204 || pURL->server_status == 201 || // from HTTP pURL->server_status == 0)); // from FTP. tapeFS->m_pfComplete(bSuccess,tapeFS->m_pArg); } // Kill the tapeFS. delete tapeFS; } void CTapeFSPublish::Complete(XP_Bool bSuccess, EDT_ITapeFileSystemComplete *pfComplete, void *pArg ) { m_pfComplete = pfComplete; m_pArg = pArg; // Count number of files we're actually publishing, may be less than // m_tempFilenames.Size() if errors occurred. int numFilesToPost = 0; for (int n = 0; n < m_tempFilenames.Size(); n++) { if (m_tempFilenames[n]) numFilesToPost++; } // Publish temp files. Temp files deleted in destructor. if (bSuccess && numFilesToPost ) { // One extra for trailing NULL. char **filesToPost = (char **)XP_ALLOC((numFilesToPost + 1) * sizeof(char*)); if ( !filesToPost ) { XP_ASSERT(0); return; } // Where to put the files on the server. // FTP publish will ignore the path info in postTo and will just use // the filename after the last slash. char **postTo = NULL; postTo = (char **)XP_ALLOC((numFilesToPost + 1) * sizeof(char*)); if ( !postTo ) { XP_ASSERT(0); XP_FREE(filesToPost); return; } // Not NULL-terminated. XP_Bool *addCRLF = (XP_Bool *)XP_ALLOC((numFilesToPost) * sizeof(XP_Bool)); if (!addCRLF) { XP_ASSERT(0); XP_FREE(filesToPost); XP_FREE(postTo); return; } // Copying filenames, reversing order or list and removing blanks at // the same time. int n,m; for ( n = 0, m = numFilesToPost - 1; n < m_tempFilenames.Size(); n++ ) { // Insert into list backwards, because NET_PublishFilesTo publishes in reverse order. // So, HTML file will be published first. if (m_tempFilenames[n]) { filesToPost[m] = XP_STRDUP(m_tempFilenames[n]); postTo[m] = XP_STRDUP(m_remoteURLs[n]); // Only first file is treated as text, rest are whatever netlib decides. // well actually only if it's not a pre-encrypted file! addCRLF[m] = (n == 0) && !IsFirstBinary(); m--; } } // Otherwise we counted numFilesToPost wrong. XP_ASSERT(m == -1); // Trailing NULL. filesToPost[numFilesToPost] = NULL; postTo[numFilesToPost] = NULL; // Temporarily remove characters after final slash // from m_pRemoteURL, so pRemoteFullURL is a directory. char *lastSlash = XP_STRRCHR(m_pRemoteURL,'/'); char saved=0; if (lastSlash) { saved = *(lastSlash + 1); *(lastSlash + 1) = '\0'; } char *pRemoteFullURL = NULL; if (!NET_MakeUploadURL(&pRemoteFullURL,m_pRemoteURL,m_pUsername,m_pPassword)) { pRemoteFullURL = NULL; // Just to be sure. } // Restore m_pRemoteURL. *(lastSlash + 1) = saved; if (!pRemoteFullURL) { return; } if (m_bIsHTTP) { // m_pRemoteURL may or may not be a directory. // username and password are passed in separately, not through the // URL, to avoid ever being displayed on screen to the user. NET_PublishFilesTo(m_pMWContext, filesToPost, postTo, addCRLF, m_pRemoteURL,m_pUsername,m_pPassword, edt_CTapeFSExit, (void *)this); } else { // pRemoteFullURL must be a directory for FTP publishing. // pRemoteFullURL contains username/password information, maybe we // should modify ns/lib/libnet/mkftp.c to deal with username/password // in the URL struct like mkhttp.c does. NET_PublishFilesTo(m_pMWContext, filesToPost, postTo, addCRLF, pRemoteFullURL,NULL,NULL, edt_CTapeFSExit, (void *)this); } // edt_CTapeFSExit will call pfComplete() and delete this. XP_FREEIF(pRemoteFullURL); } else { if (m_pfComplete) { // Pass in TRUE because CTapeFSComplete() did the right thing, even // though there may have been errors earlier on. m_pfComplete(TRUE,m_pArg); } delete this; } } char *CTapeFSPublish::makeLocal(char *baseURL,char *srcURL) { // Return value. char *ret = NULL; // Set ret to be directory to place files in. int len = XP_STRLEN(baseURL); if (len < 1) { XP_ASSERT(0); return NULL; } if (baseURL[len-1] == '/') { // baseURL is already a directory. ret = XP_STRDUP(baseURL); } else { char *trail = XP_STRRCHR(baseURL,'/'); if (trail == NULL) { XP_ASSERT(0); return NULL; } // Temporarily set the char after the last slash to NULL and copy everything before and // including the last slash. We know the '/' is not the last character, since we checked for that // above. char tmp = *(trail + 1); *(trail + 1) = '\0'; ret = XP_STRDUP(baseURL); *(trail + 1) = tmp; } char *localName = FE_URLToLocalName(srcURL); if (localName == NULL) { XP_ASSERT(0); return NULL; } if (!ret) { XP_ASSERT(0); return NULL; } ret = XP_AppendStr(ret,localName); XP_ASSERT(ret); XP_FREE(localName); return ret; } #endif // EDITOR