GME  13
Client.cpp
Go to the documentation of this file.
00001 
00023 #include "../StdAfx.h"
00024 
00025 #if(USESVN)
00026 
00027 #include ".\client.h"
00028 #include <crtdbg.h> // for ASSERT
00029 //#include <iostream> // remove this later
00030 #include "Pool.h"
00031 #include "Util.h"
00032 #include "svn_client.h"
00033 #include "svn_config.h"
00034 
00035 extern std::string g_userName;
00036 extern std::string g_passWord;
00037 
00038 Client::Client( const std::string& p_userName, const std::string& p_passWord)
00039         : m_notify2( 0)
00040         , m_prompter( 0)
00041         , m_commitMessageBuilder( 0)
00042         , m_userName( p_userName)
00043         , m_passWord( p_passWord)
00044 {
00045         Util::globalInit();
00046         setPrompt( Prompter::makePrompter( new GPromptImpl()));
00047         // we set this:
00048         notification2( new ClientUtil::NotifyHelp());
00049         m_ctx = NULL;
00050         m_ctxPool = std::auto_ptr<Pool>(new Pool());
00051 }
00052 
00053 Client::~Client(void)
00054 {
00055         if( m_prompter) delete m_prompter;
00056         m_prompter = 0;
00057 
00058         // should we delete this also?
00059         if( m_commitMessageBuilder) delete m_commitMessageBuilder;
00060         m_commitMessageBuilder = 0;
00061 
00062         notification2( 0);
00063 }
00064 
00065 void Client::notification2( ClientUtil::NotifyHelp *notify2)
00066 {
00067         if( m_notify2) delete m_notify2;
00068         m_notify2 = notify2;
00069 } 
00070 
00071 void Client::setCommitMessageHandler( ClientUtil::CommitHelp::MsgBuilder* p_commitMessageBuilder)
00072 {
00073     if( m_commitMessageBuilder) delete m_commitMessageBuilder;
00074     m_commitMessageBuilder = p_commitMessageBuilder;
00075 }
00076 
00077 
00078 void Client::setPrompt( Prompter * p_prompter)
00079 {
00080     if( m_prompter) delete m_prompter;
00081     m_prompter = p_prompter;
00082 }
00083 
00084 
00085 // not so public interface:
00086 long Client::sub_checkout(const char *moduleName, const char *destPath, 
00087                                                 Revision &revision, Revision &pegRevision, 
00088                                                 bool recurse, bool ignoreExternals)
00089 {
00090         Pool reqPool;
00091         apr_pool_t * apr_pool = reqPool.pool();
00092 
00093         if(moduleName == NULL)
00094         {
00095                 Util::throwNullPointerException("moduleName");
00096                 return -1;
00097         }
00098         if(destPath == NULL)
00099         {
00100                 Util::throwNullPointerException("destPath");
00101                 return -1;
00102         }
00103 
00104         Path url(moduleName, reqPool.pool());
00105         Path path(destPath, reqPool.pool());
00106         svn_error_t *Err = url.error_occured();
00107         if(Err != NULL)
00108         {
00109                 Util::handleSVNError(Err);
00110                 return -1;
00111         }
00112         Err = path.error_occured();
00113         if(Err != NULL)
00114         {
00115                 Util::handleSVNError(Err);
00116                 return -1;
00117         }
00118         svn_revnum_t retval;
00119 
00120         svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
00121         if(ctx == NULL)
00122         {
00123                 return -1;
00124         }
00125 
00126         Err = svn_client_checkout2 (&retval, url.c_str(),
00127                 path.c_str (),
00128                 pegRevision.revision (),
00129                 revision.revision (),
00130                 recurse, 
00131                 ignoreExternals,
00132                 ctx,
00133                 apr_pool);
00134 
00135         if(Err != NULL)
00136         {
00137                 Util::handleSVNError(Err);
00138                 return -1;
00139         }
00140         return retval;
00141 
00142 }
00143 
00144 long Client::sub_commit(Targets &targets, const char *message, bool recurse,
00145                                           bool noUnlock)
00146 {
00147         Pool reqPool;
00148         apr_pool_t * apr_pool = reqPool.pool();
00149         svn_client_commit_info_t *commit_info = NULL;
00150         const apr_array_header_t *targets2 = targets.array(reqPool);
00151         svn_error_t *Err = targets.error_occured();
00152         if(Err != NULL)
00153         {
00154                 Util::handleSVNError(Err);
00155                 return -1;
00156         }
00157         svn_client_ctx_t *ctx = getContext(message, apr_pool);
00158         if(ctx == NULL)
00159         {
00160                 return -1;
00161         }
00162         Err = svn_client_commit2 (&commit_info,
00163                 targets2,
00164                 recurse, noUnlock, ctx, apr_pool);
00165         if(Err != NULL)
00166                 Util::handleSVNError(Err);
00167 
00168         if(commit_info && SVN_IS_VALID_REVNUM (commit_info->revision))
00169                 return commit_info->revision;
00170 
00171         return -1;
00172 }
00173 
00174 long Client::sub_commit3(Targets &targets, const char *message, bool recurse,
00175                                           bool noUnlock)
00176 {
00177         Pool reqPool;
00178         apr_pool_t * apr_pool = reqPool.pool();
00179         svn_commit_info_t *commit3_info = NULL;
00180         const apr_array_header_t *targets2 = targets.array(reqPool);
00181         svn_error_t *Err = targets.error_occured();
00182         if(Err != NULL)
00183         {
00184                 Util::handleSVNError(Err);
00185                 return -1;
00186         }
00187         svn_client_ctx_t *ctx = getContext(message, apr_pool);
00188         if(ctx == NULL)
00189         {
00190                 return -1;
00191         }
00192         Err = svn_client_commit3(&commit3_info,
00193                 targets2,
00194                 recurse, noUnlock, ctx, apr_pool);
00195         if(Err != NULL)
00196                 Util::handleSVNError(Err);
00197 
00198 #if(0)
00199         typedef struct svn_commit_info_t
00200         {
00201                 svn_revnum_t revision;
00202                 const char *date;
00203                 const char *author;
00204                 const char *post_commit_err;
00205         } svn_commit_info_t;
00206 #endif
00207 
00208         if(commit3_info && SVN_IS_VALID_REVNUM (commit3_info->revision))
00209                 return commit3_info->revision;
00210 
00211         return -1;
00212 }
00213 
00214 
00215 bool Client::sub_update(Targets &targets, Revision &revision, bool recurse,
00216                                         bool ignoreExternals, std::vector< long>& res)
00217 {
00218         Pool reqPoolParent;
00219         // This function leaks if we don't use two pools
00220         Pool reqPool(reqPoolParent);
00221         apr_pool_t * apr_pool = reqPool.pool();
00222 
00223         svn_client_ctx_t *ctx = getContext(NULL, apr_pool);
00224         apr_array_header_t *retval;
00225         if(ctx == NULL)
00226         {
00227                 return false;
00228         }
00229         const apr_array_header_t *array = targets.array(reqPool);
00230         svn_error_t *Err = targets.error_occured();
00231         if(Err != NULL)
00232         {
00233                 Util::handleSVNError(Err);
00234                 return false;
00235         }
00236 
00237         try 
00238         {
00239                 Err = svn_client_update2 (&retval, array,
00240                         revision.revision (),
00241                         recurse,
00242                         ignoreExternals,
00243                         ctx,
00244                         apr_pool);
00245         }
00246         catch(...)
00247         {
00248                 ASSERT(0);
00249                 return false;
00250         }
00251 
00252         if(Err != NULL)
00253         {
00254                 Util::handleSVNError(Err);
00255                 return false;
00256         }
00257 
00258         res.resize( retval->nelts);
00259         for( int i = 0; i < retval->nelts; ++i)
00260                 res[i] = APR_ARRAY_IDX (retval, i, svn_revnum_t);
00261 
00262         return true;
00263 }
00264 
00265 bool Client::sub_cleanup(const char *path)
00266 {
00267         Pool reqPool;
00268         apr_pool_t * apr_pool = reqPool.pool();
00269         if(path == NULL)
00270         {
00271                 Util::throwNullPointerException("path");
00272                 return false;
00273         }
00274         Path intPath(path, reqPool.pool());
00275         svn_error_t *Err = intPath.error_occured();
00276         if(Err != NULL)
00277         {
00278                 Util::handleSVNError(Err);
00279                 return false;
00280         }
00281 
00282         svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
00283         if(ctx == NULL)
00284         {
00285                 return false;
00286         }
00287         Err = svn_client_cleanup (intPath.c_str (), ctx, apr_pool);
00288 
00289         if(Err != NULL)
00290         {
00291                 Util::handleSVNError(Err);
00292                 return false;
00293         }
00294 
00295         return true;
00296 }
00297 
00298 bool Client::sub_resolved(const char *path, bool recurse)
00299 {
00300         Pool reqPool;
00301         apr_pool_t * apr_pool = reqPool.pool();
00302         if(path == NULL)
00303         {
00304                 Util::throwNullPointerException("path");
00305                 return false;
00306         }
00307         Path intPath(path, reqPool.pool());
00308         svn_error_t *Err = intPath.error_occured();
00309         if(Err != NULL)
00310         {
00311                 Util::handleSVNError(Err);
00312                 return false;
00313         }
00314         svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
00315         if(ctx == NULL)
00316         {
00317                 return false;
00318         }
00319         Err = svn_client_resolved (intPath.c_str (),
00320                 recurse,
00321                 ctx,
00322                 apr_pool);
00323 
00324         if(Err != NULL)
00325         {
00326                 Util::handleSVNError(Err);
00327                 return false;
00328         }
00329 
00330         return true;
00331 }
00332 
00333 
00334 bool Client::sub_propertySet(const char *path, const char *name, 
00335                                                 const char *value, bool recurse, bool force)
00336 {
00337         Pool reqPool;
00338         if(path == NULL)
00339         {
00340                 Util::throwNullPointerException("path");
00341                 return false;
00342         }
00343         if(name == NULL)
00344         {
00345                 Util::throwNullPointerException("name");
00346                 return false;
00347         }
00348         if(value == NULL)
00349         {
00350                 Util::throwNullPointerException("value");
00351                 return false;
00352         }
00353         svn_string_t *val = svn_string_create(value, reqPool.pool());
00354 
00355 
00356         //propertySet(path, name, val->data, recurse, force);                     // modified from val to val->data
00357     //Path intPath(path, reqPool.pool());
00358     svn_error_t *Err = NULL; // intPath.error_occured();
00359     if(Err != NULL)
00360     {
00361         Util::handleSVNError(Err);
00362         return false;
00363     }
00364 
00365     svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
00366     if(ctx == NULL)
00367         return false;
00368     Err = svn_client_propset2 (name, val, 
00369                                 path,
00370                                 recurse, 
00371                                 force,
00372                                 ctx,
00373                                                                 reqPool.pool());
00374     if(Err!= NULL)
00375         {
00376         Util::handleSVNError(Err); // previously just handled the error and fall through to return true
00377                 return false;
00378         }
00379 
00380         return true;
00381 }
00382 
00383 bool Client::sub_lock(Targets &targets, const char *comment, 
00384                 bool force)
00385 {
00386         Pool reqPool;
00387         const apr_array_header_t *targetsApr = targets.array(reqPool);
00388         svn_error_t *Err = targets.error_occured();
00389         if(Err != NULL)
00390         {
00391                 Util::handleSVNError(Err);
00392                 return false;
00393         }
00394         apr_pool_t * apr_pool = reqPool.pool();
00395         svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
00396         Err = svn_client_lock(targetsApr, comment, force, ctx, apr_pool);
00397 
00398         if (Err != NULL)
00399         {
00400                 Util::handleSVNError(Err);
00401                 return false;
00402         }
00403 
00404         return true;
00405 }
00406 
00407 //svn_error_t *
00408 //svn_client_unlock(const apr_array_header_t *targets,
00409 //                  svn_boolean_t break_lock,
00410 //                  svn_client_ctx_t *ctx,
00411 //                  apr_pool_t *pool)
00412 
00413 bool Client::sub_unlock(Targets &targets)
00414 {
00415         Pool reqPool;
00416         const apr_array_header_t *targetsApr = targets.array(reqPool);
00417         svn_error_t *Err = targets.error_occured();
00418         if(Err != NULL)
00419         {
00420                 Util::handleSVNError(Err);
00421                 return false;
00422         }
00423         apr_pool_t * apr_pool = reqPool.pool();
00424         svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
00425         Err = svn_client_unlock(targetsApr, true, ctx, apr_pool);
00426 
00427         if (Err != NULL)
00428         {
00429                 Util::handleSVNError(Err);
00430                 return false;
00431         }
00432 
00433         return true;
00434 }
00435 
00436 
00437 ClientUtil::StatusInfo Client::sub_single_status(const char *path, bool onServer)
00438 {
00439         ClientUtil::StatusInfo null_pair;
00440         ClientUtil::StatusHelp::StatusBaton statusBaton;
00441         Pool reqPool;
00442         svn_revnum_t youngest = SVN_INVALID_REVNUM;
00443         svn_opt_revision_t rev;
00444 
00445         if(path == NULL)
00446         {
00447                 Util::throwNullPointerException("path");
00448                 return null_pair;
00449         }
00450 
00451         svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
00452         if(ctx == NULL)
00453         {
00454                 return null_pair;
00455         }
00456 
00457 
00458         rev.kind = svn_opt_revision_unspecified;
00459         statusBaton.m_pool = reqPool.pool();
00460         Path intPath(path, reqPool.pool());
00461         svn_error_t *Err = intPath.error_occured();
00462         if(Err != NULL)
00463         {
00464                 Util::handleSVNError(Err);
00465                 return null_pair;
00466         }
00467 
00468         Err = svn_client_status2 (&youngest, intPath.c_str(), &rev, 
00469                 ClientUtil::StatusHelp::statusReceiver, // callback of type svn_wc_status_func2_t
00470                 &statusBaton,   // callback's parameter
00471                 FALSE,          // DESCEND
00472                 TRUE,           // get_All
00473                 onServer ? TRUE : FALSE,     //update
00474                 FALSE,          // no_ignore,
00475                 FALSE,          // ignore externals
00476                 ctx,
00477                 reqPool.pool());
00478 
00479         if(Err == NULL)
00480         {
00481                 int size = (int) statusBaton.m_statusVect.size();
00482                 if (size == 0)
00483                         return null_pair;
00484 
00485                 // when svn_client_status is used with a directory, the status of the 
00486                 // directory itself and the status of all its direct children are 
00487                 // returned
00488                 // we just want the status of the directory (ie the status of the 
00489                 // element with the shortest path)
00490                 int j = 0;
00491                 for (int i = 0; i < size; i++)
00492                 {
00493                         if (strlen(statusBaton.m_statusVect[i].m_path) < 
00494                                 strlen(statusBaton.m_statusVect[j].m_path))
00495                                 j = i;
00496                 }
00497 
00498                 null_pair.first = statusBaton.m_statusVect[j].m_path;
00499                 null_pair.second = (statusBaton.m_statusVect[j].m_status)? 1:0;
00500 
00501                 //typedef struct svn_wc_status2_t
00502                 //{
00503                 //      svn_wc_entry_t *entry;
00504                 //      enum svn_wc_status_kind text_status;
00505                 //      enum svn_wc_status_kind prop_status;
00506                 //      svn_boolean_t locked;
00507                 //      svn_boolean_t copied;
00508                 //      svn_boolean_t switched;
00509                 //      enum svn_wc_status_kind repos_text_status;
00510                 //      enum svn_wc_status_kind repos_prop_status;
00511                 //      svn_lock_t *repos_lock;
00512                 //      const char *url;
00513                 //      svn_revnum_t ood_last_cmt_rev;
00514                 //      apr_time_t ood_last_cmt_date;
00515                 //      svn_node_kind_t ood_kind;
00516                 //      const char *ood_last_cmt_author;
00517                 //} svn_wc_status2_t;
00518 
00519                 return null_pair;
00520         }
00521         else
00522         {
00523                 Util::handleSVNError(Err);
00524                 return null_pair;
00525         }
00526 }
00527 
00528 // locked status not reported correctly
00529 // use info instead
00530 ClientUtil::StatusExtInfoVec Client::sub_extended_status( const char *p_path, bool p_onServer)
00531 {
00532         ClientUtil::StatusExtInfoVec res;
00533         ClientUtil::StatusHelp::StatusBaton statusBaton;
00534         Pool reqPool;
00535         svn_revnum_t youngest = SVN_INVALID_REVNUM;
00536         svn_opt_revision_t rev;
00537 
00538         if(p_path == NULL)
00539         {
00540                 Util::throwNullPointerException("p_path");
00541                 return res;
00542         }
00543 
00544         svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
00545         if(ctx == NULL)
00546         {
00547                 return res;
00548         }
00549 
00550 
00551         rev.kind = svn_opt_revision_unspecified;
00552         statusBaton.m_pool = reqPool.pool();
00553         Path intPath(p_path, reqPool.pool());
00554         svn_error_t *Err = intPath.error_occured();
00555         if(Err != NULL)
00556         {
00557                 Util::handleSVNError(Err);
00558                 return res;
00559         }
00560 
00561         Err = svn_client_status2 (&youngest, intPath.c_str(), &rev, 
00562                 ClientUtil::StatusHelp::statusReceiver, // callback of type svn_wc_status_func2_t
00563                 &statusBaton,   // callback's parameter
00564                 FALSE,          // DESCEND
00565                 TRUE,           // get_All
00566                 p_onServer ? TRUE : FALSE,     //update
00567                 FALSE,          // no_ignore,
00568                 FALSE,          // ignore externals
00569                 ctx,
00570                 reqPool.pool());
00571 
00572         if(Err == NULL)
00573         {
00574                 int size = (int) statusBaton.m_statusVect.size();
00575                 if (size == 0)
00576                         return res;
00577 
00578                 // when svn_client_status is used with a directory, the status of the 
00579                 // directory itself and the status of all its direct children are 
00580                 // returned
00581                 // we just want the status of the directory (ie the status of the 
00582                 // element with the shortest path)
00583                 int j = 0;
00584                 for (int i = 0; i < size; i++)
00585                 {
00586                         //if( statusBaton.m_statusVect[i].m_status->locked)
00587                         //      std::cout << "Stat " << "Locked" << std::endl;
00588                         //else
00589                         //      std::cout << "Stat " << "NotLocked" << std::endl;
00590                         ClientUtil::StatusExtInfo r = statusBaton.m_statusVect[i];
00591                         res.push_back( r);
00592                 }
00593 
00594                 //typedef struct svn_wc_status2_t
00595                 //{
00596                 //      svn_wc_entry_t *entry;
00597                 //      enum svn_wc_status_kind text_status;
00598                 //      enum svn_wc_status_kind prop_status;
00599                 //      svn_boolean_t locked;
00600                 //      svn_boolean_t copied;
00601                 //      svn_boolean_t switched;
00602                 //      enum svn_wc_status_kind repos_text_status;
00603                 //      enum svn_wc_status_kind repos_prop_status;
00604                 //      svn_lock_t *repos_lock;
00605                 //      const char *url;
00606                 //      svn_revnum_t ood_last_cmt_rev;
00607                 //      apr_time_t ood_last_cmt_date;
00608                 //      svn_node_kind_t ood_kind;
00609                 //      const char *ood_last_cmt_author;
00610                 //} svn_wc_status2_t;
00611 
00612                 return res;
00613         }
00614         else
00615         {
00616                 Util::handleSVNError(Err);
00617                 return res;
00618         }
00619 }
00620 
00621 
00622 svn_client_ctx_t * Client::getContext(const char *p_strMessage, apr_pool_t *pool)
00623 {
00624         if (m_ctx == NULL)
00625         {
00626                 m_ctx = createContext(NULL, m_ctxPool->pool());
00627         }
00628         m_commitMessage = p_strMessage ? p_strMessage : "Empty";
00629         ((ClientUtil::CommitHelp::LogMsgBaton*)m_ctx->log_msg_baton2)->m_message = m_commitMessage.c_str();
00630         return m_ctx;
00631 }
00632 
00633 svn_client_ctx_t * Client::createContext(const char *p_strMessage, apr_pool_t *pool)
00634 {
00635         svn_auth_baton_t *ab;
00636         svn_client_ctx_t *ctx;
00637         svn_error_t *err = NULL;
00638         if (( err = svn_client_create_context(&ctx, pool)))
00639         {
00640                 Util::handleSVNError(err);
00641                 return NULL;
00642         }
00643 
00644         apr_array_header_t *providers
00645                 = apr_array_make (pool, 10, sizeof (svn_auth_provider_object_t *));
00646 
00647         /* The main disk-caching auth providers, for both
00648         'username/password' creds and 'username' creds.  */
00649         svn_auth_provider_object_t *provider; // provider->vtable->save_credentials is a function pointer to saving to the cache
00650 #ifdef WIN32
00651         svn_client_get_windows_simple_provider (&provider, pool);
00652         APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00653 #endif
00654         svn_client_get_simple_provider (&provider, pool);
00655         APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00656         svn_client_get_username_provider (&provider, pool);
00657         APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00658 
00659         /* The server-cert, client-cert, and client-cert-password providers. */
00660         svn_client_get_ssl_server_trust_file_provider (&provider, pool);
00661         APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00662         svn_client_get_ssl_client_cert_file_provider (&provider, pool);
00663         APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00664         svn_client_get_ssl_client_cert_pw_file_provider (&provider, pool);
00665         APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00666 
00667         if(m_prompter != NULL)
00668         {
00669                 /* Two basic prompt providers: username/password, and just username.*/
00670                 provider = m_prompter->getProviderSimple(pool);
00671                 APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00672 
00673                 provider = m_prompter->getProviderUsername(pool);
00674                 APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00675 
00676                 /* Three ssl prompt providers, for server-certs, client-certs,
00677                 and client-cert-passphrases.  */
00678                 provider = m_prompter->getProviderServerSSLTrust(pool);
00679                 APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00680 
00681                 provider = m_prompter->getProviderClientSSL(pool);
00682                 APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00683 
00684                 provider = m_prompter->getProviderClientSSLPassword(pool);
00685                 APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
00686         }
00687 
00688 
00689 
00690         /* Build an authentication baton to give to libsvn_client. */
00691         svn_auth_open (&ab, providers, pool);
00692 
00693         /* Place any default --username or --password credentials into the
00694         auth_baton's run-time parameter hash.  ### Same with --no-auth-cache? */
00695         if (!m_userName.empty())
00696                 svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_USERNAME, m_userName.c_str());
00697         else if( !g_userName.empty()) // g_userName is NOT empty => g_userName != m_userName
00698                 svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_USERNAME, g_userName.c_str()); // this might have been filled by prompt()
00699         
00700         if (!m_passWord.empty())
00701                 svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD, m_passWord.c_str());
00702         else if( !g_passWord.empty()) // g_passWord is NOT empty => g_passWord != m_passWord
00703                 svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD, g_passWord.c_str()); // this might have been filled by prompt()
00704 
00705         //svn_auth_set_parameter(ab, SVN_AUTH_CRED_SSL_CLIENT_CERT, 
00706 
00707         ctx->auth_baton = ab;
00708 
00709         ctx->notify_func  = 0;//Notify::notify;
00710         ctx->notify_baton = 0;//m_notify;
00711         
00712         ctx->notify_func2  = ClientUtil::NotifyHelp::notify2;
00713         ctx->notify_baton2 = m_notify2;
00714         
00715         // a callback to be used to see if we (the client) wish to cancel the running operation
00716         // client's cancelOperation() public method allows users to ask for cancel
00717 
00718         ctx->cancel_func  = ClientUtil::OtherHelp::checkCancel;
00719         ctx->cancel_baton = this;
00720 
00721         m_cancelOperation = false;
00722 
00723         // 1.2 logic with log_msg
00724         //ctx->log_msg_func = getCommitMessage;                    // used by commit
00725         //ctx->log_msg_baton = getCommitMessageBaton(message);     // ditto
00726 
00727         // 1.3 logic?
00728         // if not filled (is NULL) means that Subversion should try log_msg_func
00729         ctx->log_msg_baton2 = ClientUtil::CommitHelp::createLogMsgBaton(p_strMessage, m_commitMessageBuilder, pool);
00730         ctx->log_msg_func2  = ClientUtil::CommitHelp::logMsg;
00731 
00732         ctx->log_msg_baton  = 0; // safety 1st
00733         ctx->log_msg_func   = 0;
00734 
00735         const char *configDir = m_configDir.c_str();
00736         if(m_configDir.length() == 0)
00737                 configDir = NULL;
00738         if (( err = 
00739                 svn_config_get_config (&(ctx->config), configDir, pool)))
00740         {
00741                 Util::handleSVNError(err);
00742                 return NULL;
00743         }
00744 
00745         // no progress feedback yet
00746         ctx->progress_func  = 0;
00747         ctx->progress_baton = 0;
00748 
00749 
00750         // Use custom ssh client "GMEplink" (no console window)
00751         CString appPath;
00752         ::GetModuleFileName(NULL, appPath.GetBuffer(MAX_PATH), MAX_PATH);
00753         appPath.ReleaseBuffer();
00754         appPath = appPath.Left(appPath.ReverseFind('\\')+1);
00755         svn_config_t * cfg = (svn_config_t *)apr_hash_get (ctx->config, SVN_CONFIG_CATEGORY_CONFIG,
00756                         APR_HASH_KEY_STRING);
00757         const char * sshValue = NULL;
00758         svn_config_get(cfg, &sshValue, SVN_CONFIG_SECTION_TUNNELS, "ssh", "");
00759         if ((sshValue == NULL)||(sshValue[0] == 0)) {
00760                 CString tsvn_ssh = _T("\"") + appPath + _T("GMEplink.exe") + _T("\"");
00761                 tsvn_ssh.Replace('\\', '/');
00762                 svn_config_set(cfg, SVN_CONFIG_SECTION_TUNNELS, "ssh", tsvn_ssh);
00763         }
00764 
00765         svn_config_set(cfg, SVN_CONFIG_SECTION_MISCELLANY, SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, false);
00766 
00767         return ctx;
00768 }
00769 
00770 void ClientUtil::CommitHelp::MsgBuilder::dealWithItem( std::string& res, svn_client_commit_item_t * item)
00771 {
00772         //const char *      item->path
00773         //svn_node_kind_t   item->kind;
00774         //const char *      item->url;
00775         //const char *      item->copyfrom_url;
00776         //svn_revnum_t      item->revision;
00777         if( !item)
00778         {
00779                 res += "<Null item>\n";
00780                 return;
00781         }
00782 
00783         if(item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
00784                 res += "[Add]";
00785         if(item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
00786                 res += "[Del]";
00787         if(item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS)
00788                 res += "[Mod]";
00789         if(item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS)
00790                 res += "[Pro]";
00791         if(item->state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY)
00792         {
00793                 res += "[Cop]";
00794                 res += "From: "; res += ClientUtil::charstar2str( item->copyfrom_url, "CopyFromURL");
00795         }
00796 
00797         char buff[32]; itoa( item->revision, &buff[0], 10);
00798         res += " Rev#"; res += buff; 
00799         res += " "; 
00800         res += ClientUtil::charstar2str( item->path, "Path");
00801         res += "\n";
00802 }
00803 
00804 std::string ClientUtil::CommitHelp::MsgBuilder::build(const apr_array_header_t *commit_items)
00805 {
00806         std::string m;
00807         if( !commit_items) return m;
00808 
00809         int count = commit_items->nelts;
00810         for(int i = 0; i < count; i++)
00811         {
00812                 // get the commit item
00813                 svn_client_commit_item_t *item
00814                         = ((svn_client_commit_item_t **) commit_items->elts)[i];
00815 
00816                 dealWithItem( m, item);
00817         }
00818 
00819         return m;
00820 }
00821 
00843 // static, callback method
00844 svn_error_t * ClientUtil::CommitHelp::logMsg(const char **log_msg,
00845                                                                                 const char **tmp_file,
00846                                                                                 const apr_array_header_t *commit_items,
00847                                                                                 void *baton,
00848                                                                                 apr_pool_t *pool)
00849 {
00850         *log_msg = NULL;
00851         *tmp_file = NULL;
00852         LogMsgBaton *lmb = (LogMsgBaton *) baton; // convert the baton to the specific structure we passed in
00853 
00854         // is there a message composer?
00855         if (lmb && lmb->m_messageHandler)
00856         {
00857                 // build special message based on the to-be-commited-items array
00858                 std::string spec_msg = lmb->m_messageHandler->build( commit_items);
00859                 *log_msg = apr_pstrdup( pool, spec_msg.c_str()); 
00860                 return SVN_NO_ERROR;
00861         }
00862         else if (lmb && lmb->m_message) // or at least a message?
00863         {
00864                 *log_msg = apr_pstrdup (pool, lmb->m_message);
00865                 return SVN_NO_ERROR;
00866         }
00867 
00868         return SVN_NO_ERROR;
00869 }
00870 
00871 // static 
00872 void * ClientUtil::CommitHelp::createLogMsgBaton( const char * p_strMessage, CommitHelp::MsgBuilder * p_msgComposer, apr_pool_t *pool)
00873 {
00874         // the baton created by this method will affect 
00875         // how CommitHelp::logMsg() will deal with the 
00876         // array of commit_items
00877 
00878         if( p_strMessage != NULL || p_msgComposer)
00879         {
00880                 LogMsgBaton *baton = (LogMsgBaton *) apr_palloc (pool, sizeof (*baton));
00881 
00882                 baton->m_message = p_strMessage; // beware: ptr assignment only !!
00883                 baton->m_messageHandler = p_msgComposer;
00884 
00885                 return baton;
00886         }
00887         //return NULL;
00888         
00889         // create a baton with dummy string value for empty p_strMessages as well:
00890         static const char * def_str = "Default";
00891         LogMsgBaton *baton = (LogMsgBaton *) apr_palloc (pool, sizeof (*baton));
00892         baton->m_message = def_str; // beware: ptr assignment only !!
00893         return baton;
00894 }
00895 
00896 void Client::cancelOperation()
00897 {
00898         m_cancelOperation = true;
00899 }
00900 
00901 // static, callback method
00902 svn_error_t * ClientUtil::OtherHelp::checkCancel(void *cancelBaton)
00903 {
00904         Client *that = (Client*)cancelBaton;
00905         if(that->m_cancelOperation)
00906                 return svn_error_create (SVN_ERR_CANCELLED, NULL,
00907                 "Operation canceled");
00908         else
00909                 return SVN_NO_ERROR;
00910 }
00911 
00912 // static, callback method, conforms to svn_wc_status_func2_t
00913 void ClientUtil::StatusHelp::statusReceiver( void *baton, const char *path, 
00914                 svn_wc_status2_t *status)
00915 {
00916         StatusBaton *status_baton = (StatusBaton*) baton;
00917         StatusEntry status_entry;
00918         status_entry.m_path = apr_pstrdup( status_baton->m_pool, path);
00919         status_entry.m_status = svn_wc_dup_status2( status, status_baton->m_pool);
00920         status_baton->m_statusVect.push_back( status_entry);
00921 }
00922 
00930 void ClientUtil::NotifyHelp::notify2( void *baton,
00931                                                                 const svn_wc_notify_t *notify,
00932                                                                 apr_pool_t *pool)
00933 {
00934         // Notify the world that @a notify->action has happened to @a notify->path.
00935 
00936         // a NotifyHelp object is used as the baton
00937         NotifyHelp * that = (NotifyHelp *) baton;
00938         if( that) // sanity check
00939         {
00940                 // call our method
00941                 that->onNotify( notify, pool);
00942         }
00943 }
00944 
00945 // we deal with the notification that the @a notify->action has happened to @a notify->path.
00946 void ClientUtil::NotifyHelp::onNotify( const svn_wc_notify_t *notify, apr_pool_t *pool)
00947 {
00948         if (notify->action == svn_wc_notify_failed_lock) {
00949                 char errbuff[BUFSIZ];
00950                 const char* errbuff2 = svn_err_best_message(notify->err, errbuff, BUFSIZ);
00951                 m_msg.append(errbuff2 ? errbuff2 : errbuff);
00952                 m_msg.append("<br>"); // This is a terrible hack
00953                 m_OK = false;
00954         }
00955 }
00956 
00957 //
00958 bool Client::info2Qck( const char* p_path, bool p_recurse, ClientUtil::InfoHelp::InfoVec& p_infoVect, bool p_suppressErrorMsg)
00959 {
00960         return sub_info2( p_path, Revision(), Revision(), p_recurse, p_infoVect, p_suppressErrorMsg);
00961 }
00962 
00963 bool Client::sub_info2(const char *path, Revision &revision, Revision &pegRevision, bool recurse, ClientUtil::InfoHelp::InfoVec& p_infoVect, bool p_suppressIllegalUrlErrorMsg)
00964 {
00965         ClientUtil::InfoHelp::InfoBaton info_baton;
00966         Pool reqPool;
00967 
00968         if(path == NULL)
00969         {
00970                 Util::throwNullPointerException("path");
00971                 return false;
00972         }
00973 
00974         svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
00975         if(ctx == NULL)
00976         {
00977                 return false;
00978         }
00979         Path checkedPath(path, reqPool.pool());
00980         svn_error_t *Err = checkedPath.error_occured();
00981         if(Err != NULL)
00982         {
00983                 Util::handleSVNError(Err);
00984                 return false;
00985         }
00986 
00987         info_baton.m_pool = reqPool.pool();
00988 
00989         Err = svn_client_info (
00990                 checkedPath.c_str(), 
00991                 pegRevision.revision(),
00992                 revision.revision(),
00993                 ClientUtil::InfoHelp::infoReceiver, // callback function 
00994                 &info_baton,             // callback function's input baton parameter
00995                 recurse ? TRUE :FALSE,
00996                 ctx,
00997                 reqPool.pool());
00998 
00999         if (Err == NULL)
01000         {
01001                 p_infoVect = info_baton.m_infoVect; // copy the vector, could also use apr specific copier?
01002                 return true;
01003         }
01004         else
01005         {
01006                 // suppress SVN_ERR_RA_ILLEGAL_URL and SVN_ERR_ENTRY_MISSING_URL only, if allowed by p_suppressIllegalUrlErrorMsg
01007                 if( !p_suppressIllegalUrlErrorMsg ||
01008                         p_suppressIllegalUrlErrorMsg && Err->apr_err != SVN_ERR_RA_ILLEGAL_URL && Err->apr_err != SVN_ERR_ENTRY_MISSING_URL)
01009                                 Util::handleSVNError(Err);
01010                 return false;
01011         }
01012 }
01013 
01014 // static, callback method
01015 svn_error_t *ClientUtil::InfoHelp::infoReceiver(void *baton, 
01016                                                                   const char *path,
01017                                                                   const svn_info_t *info,
01018                                                                   apr_pool_t *pool)
01019 {
01020         // we don't create here java Status object as we don't want too many local 
01021         // references
01022         InfoBaton *info_baton = (InfoBaton*) baton; // convert the baton to the specific structure we passed in
01023         InfoEntry info_entry;
01024         info_entry.m_path = apr_pstrdup( info_baton->m_pool, path);
01025         info_entry.m_info = (svn_info_t*) apr_pcalloc ( info_baton->m_pool, sizeof(svn_info_t));
01026         info_entry.m_info->URL = apr_pstrdup( info_baton->m_pool,info->URL);
01027         info_entry.m_info->rev = info->rev;
01028         info_entry.m_info->kind = info->kind;
01029         info_entry.m_info->repos_root_URL = apr_pstrdup(info_baton->m_pool, 
01030                 info->repos_root_URL);
01031         info_entry.m_info->repos_UUID = apr_pstrdup( info_baton->m_pool, info->repos_UUID);
01032         info_entry.m_info->last_changed_rev = info->last_changed_rev;
01033         info_entry.m_info->last_changed_date = info->last_changed_date;
01034         info_entry.m_info->last_changed_author = apr_pstrdup(info_baton->m_pool, 
01035                 info->last_changed_author);
01036         if(info->lock != NULL)
01037                 info_entry.m_info->lock = svn_lock_dup( info->lock, info_baton->m_pool);
01038         else
01039                 info_entry.m_info->lock = NULL;
01040         info_entry.m_info->has_wc_info = info->has_wc_info;
01041         info_entry.m_info->schedule = info->schedule;
01042         info_entry.m_info->copyfrom_url = apr_pstrdup( info_baton->m_pool, 
01043                 info->copyfrom_url);
01044         info_entry.m_info->copyfrom_rev = info->copyfrom_rev;
01045         info_entry.m_info->text_time = info->text_time;
01046         info_entry.m_info->prop_time = info->prop_time;
01047         info_entry.m_info->checksum = apr_pstrdup( info_baton->m_pool, info->checksum);
01048         info_entry.m_info->conflict_old = apr_pstrdup( info_baton->m_pool, 
01049                 info->conflict_old);
01050         info_entry.m_info->conflict_new = apr_pstrdup( info_baton->m_pool,
01051                 info->conflict_new);
01052         info_entry.m_info->conflict_wrk = apr_pstrdup( info_baton->m_pool,
01053                 info->conflict_wrk);
01054         info_entry.m_info->prejfile = apr_pstrdup( info_baton->m_pool, info->prejfile);
01055 
01056         info_baton->m_infoVect.push_back( info_entry);
01057         return SVN_NO_ERROR;
01058 }
01059 
01060 int Client::sub_add( const char *p_pathOrUrl, bool p_rec)
01061 {
01062         Pool reqPool;
01063         apr_pool_t * apr_pool = reqPool.pool();
01064 
01065         if(p_pathOrUrl == NULL)
01066         {
01067                 Util::throwNullPointerException("p_pathOrUrl");
01068                 return -1;
01069         }
01070 
01071         Path url(p_pathOrUrl, reqPool.pool());
01072 
01073         svn_error_t *Err = url.error_occured();
01074         if(Err != NULL)
01075         {
01076                 Util::handleSVNError(Err);
01077                 return -1;
01078         }
01079 
01080         svn_client_ctx_t *ctx = getContext(NULL, reqPool.pool());
01081         if(ctx == NULL)
01082         {
01083                 return -1;
01084         }
01085 
01086         Err = svn_client_add3 ( url.c_str(),
01087                 p_rec, // recursive
01088                 true,  //force
01089                 true,  // no ignore
01090                 ctx,
01091                 apr_pool);
01092 
01093         if(Err != NULL)
01094         {
01095                 Util::handleSVNError(Err);
01096                 return -1;
01097         }
01098         return 1;
01099 }
01100 
01101 
01102 long Client::sub_mkdir(Targets &targets, const char * p_msg)
01103 {
01104         Pool reqPool;
01105         apr_pool_t * apr_pool = reqPool.pool();
01106         svn_client_commit_info_t *commit_info = NULL;
01107         // 
01108         // svn_client_mkdir takes svn_client_commit_info_t
01109         // svn_client_mkdir2 takes svn_commit_info_t
01110         //
01111         const apr_array_header_t *targets2 = targets.array(reqPool);
01112         svn_error_t *Err = targets.error_occured();
01113         if(Err != NULL)
01114         {
01115                 Util::handleSVNError(Err);
01116                 return -1;
01117         }
01118         svn_client_ctx_t *ctx = getContext(p_msg, reqPool.pool());
01119         if(ctx == NULL)
01120         {
01121                 return -1;
01122         }
01123 
01124         Err = svn_client_mkdir( &commit_info,
01125                 targets2, // paths
01126                 ctx,
01127                 apr_pool);
01128 
01129         if(Err != NULL)
01130                 Util::handleSVNError(Err);
01131 
01132         if(commit_info && SVN_IS_VALID_REVNUM (commit_info->revision))
01133                 return commit_info->revision;
01134 
01135         return -1;
01136 }
01137 
01138 long Client::sub_mkdir2( Targets& targets, const char * p_msg)
01139 {
01140         Pool reqPool;
01141         apr_pool_t * apr_pool = reqPool.pool();
01142         svn_commit_info_t        *commit2_info = NULL;
01143 
01144         const apr_array_header_t *targets2 = targets.array(reqPool);
01145         svn_error_t *Err = targets.error_occured();
01146         if(Err != NULL)
01147         {
01148                 Util::handleSVNError(Err);
01149                 return -1;
01150         }
01151         svn_client_ctx_t *ctx = getContext(p_msg, reqPool.pool());
01152         if(ctx == NULL)
01153         {
01154                 return -1;
01155         }
01156 
01157         Err = svn_client_mkdir2( &commit2_info,
01158                 targets2, // paths
01159                 ctx,
01160                 apr_pool);
01161 
01162         if(Err != NULL)
01163                 Util::handleSVNError(Err);
01164 
01165         if( commit2_info && SVN_IS_VALID_REVNUM (commit2_info->revision))
01166                 return commit2_info->revision;
01167 
01168         return -1;
01169 }
01170 
01171 //
01172 // std::string.append( const char * ) crashes if parameter ptr is 0, that's why this function is useful
01173 //
01174 // static 
01175 std::string ClientUtil::charstar2str( const char* p_charStar, const std::string p_name)
01176 {
01177         if( p_charStar)
01178         {
01179                 return std::string( p_charStar);
01180         }
01181 
01182         return std::string( "<no" + p_name + ">");
01183 }
01184 
01185 #endif