subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From julianf...@apache.org
Subject svn commit: r1720118 - in /subversion/trunk: subversion/include/private/ subversion/libsvn_delta/ tools/dev/svnmover/
Date Tue, 15 Dec 2015 11:31:30 GMT
Author: julianfoad
Date: Tue Dec 15 11:31:30 2015
New Revision: 1720118

URL: http://svn.apache.org/viewvc?rev=1720118&view=rev
Log:
In 'svnmover', consolidate some branching methods: merge the 'branch' and
'open_branch' methods into one.

* subversion/include/private/svn_branch.h
  (svn_branch__txn_open_branch): Add a 'tree_ref' parameter.
  (svn_branch__txn_branch): Delete.

* subversion/include/private/svn_branch_impl.h
  (svn_branch__txn_v_open_branch_t): Add a 'tree_ref' parameter.
  (svn_branch__txn_v_branch_t): Delete.
  (svn_branch__txn_vtable_t): Remove that method from the vtable.

* subversion/libsvn_delta/branch.c
  (branch_txn_open_branch): Add a 'tree_ref' parameter, and apply it like
    the 'branch' method used to do.
  (branch_txn_branch): Delete.
  (svn_branch__txn_open_branch): Add a 'tree_ref' parameter.
  (svn_branch__txn_branch): Delete.
  (branch_txn_create): Remove that method from the vtable.

* subversion/libsvn_delta/branch_compat.c
  (compat_branch_txn_open_branch): Add a 'tree_ref' parameter.
  (compat_branch_txn_branch): Delete.
  (svn_branch__compat_txn_from_delta_for_commit): Remove that method from
    the vtable.

* subversion/libsvn_delta/branch_nested.c
  (svn_branch__instantiate_elements_r): Update caller: pass null.
  (nested_branch_txn_open_branch): Add a 'tree_ref' parameter, and apply
    recursion to it like nested_branch_txn_branch() used to do.
  (nested_branch_txn_branch): Delete.
  (svn_branch__nested_txn_create): Remove that method from the vtable.

* tools/dev/svnmover/merge3.c
  (merge_subbranch): Use 'open_branch' instead of 'branch' method.

* tools/dev/svnmover/svnmover.c
  (svn_branch__replay,
   update_wc_base_r,
   do_mkbranch): Update caller: pass null.
  (do_branch,
   do_topbranch): Use 'open_branch' instead of 'branch' method.

Modified:
    subversion/trunk/subversion/include/private/svn_branch.h
    subversion/trunk/subversion/include/private/svn_branch_impl.h
    subversion/trunk/subversion/libsvn_delta/branch.c
    subversion/trunk/subversion/libsvn_delta/branch_compat.c
    subversion/trunk/subversion/libsvn_delta/branch_nested.c
    subversion/trunk/tools/dev/svnmover/merge3.c
    subversion/trunk/tools/dev/svnmover/svnmover.c

Modified: subversion/trunk/subversion/include/private/svn_branch.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_branch.h?rev=1720118&r1=1720117&r2=1720118&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_branch.h (original)
+++ subversion/trunk/subversion/include/private/svn_branch.h Tue Dec 15 11:31:30 2015
@@ -209,9 +209,14 @@ svn_branch__txn_new_eid(svn_branch__txn_
  * When creating a new branch, declare its root element id to be ROOT_EID. Do
  * not instantiate the root element, nor any other elements.
  *
- * ### TODO: Change this: Allow specifying the initial tree state, by
- *     reference to a committed tree. (Default / typically: the main
- *     parent in 'history' param.) 'empty' is a common and valid option.
+ * TREE_REF specifies the initial tree content, by reference to a committed
+ * tree. It overwrites any existing tree, even if the branch was already
+ * mutable in the txn.
+ *
+ * If TREE_REF is null, then the initial tree is empty for a new branch
+ * (not already present in the txn), or the branch's current tree if the
+ * branch was already present (readable or mutable) in the txn.
+ *
  * ### TODO: Take a 'history' parameter; 'none' is a valid option.
  *
  * We use a common 'open subbranch' method for both 'find' and 'add'
@@ -229,17 +234,10 @@ svn_branch__txn_open_branch(svn_branch__
                             svn_branch__state_t **new_branch_p,
                             const char *branch_id,
                             int root_eid,
+                            svn_branch__rev_bid_eid_t *tree_ref,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool);
 
-svn_error_t *
-svn_branch__txn_branch(svn_branch__txn_t *txn,
-                       svn_branch__state_t **new_branch_p,
-                       svn_branch__rev_bid_eid_t *from,
-                       const char *new_branch_id,
-                       apr_pool_t *result_pool,
-                       apr_pool_t *scratch_pool);
-
 /** Register a sequence point.
  *
  * At a sequence point, elements are arranged in a tree hierarchy: each

Modified: subversion/trunk/subversion/include/private/svn_branch_impl.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_branch_impl.h?rev=1720118&r1=1720117&r2=1720118&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_branch_impl.h (original)
+++ subversion/trunk/subversion/include/private/svn_branch_impl.h Tue Dec 15 11:31:30 2015
@@ -79,14 +79,7 @@ typedef svn_error_t *(*svn_branch__txn_v
   svn_branch__state_t **new_branch_p,
   const char *new_branch_id,
   int root_eid,
-  apr_pool_t *result_pool,
-  apr_pool_t *scratch_pool);
-
-typedef svn_error_t *(*svn_branch__txn_v_branch_t)(
-  svn_branch__txn_t *txn,
-  svn_branch__state_t **new_branch_p,
   svn_branch__rev_bid_eid_t *from,
-  const char *new_branch_id,
   apr_pool_t *result_pool,
   apr_pool_t *scratch_pool);
 
@@ -121,7 +114,6 @@ struct svn_branch__txn_vtable_t
   svn_branch__txn_v_get_num_new_eids_t get_num_new_eids;
   svn_branch__txn_v_new_eid_t new_eid;
   svn_branch__txn_v_open_branch_t open_branch;
-  svn_branch__txn_v_branch_t branch;
   svn_branch__txn_v_finalize_eids_t finalize_eids;
   svn_branch__txn_v_serialize_t serialize;
   svn_branch__txn_v_sequence_point_t sequence_point;

Modified: subversion/trunk/subversion/libsvn_delta/branch.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/branch.c?rev=1720118&r1=1720117&r2=1720118&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/branch.c (original)
+++ subversion/trunk/subversion/libsvn_delta/branch.c Tue Dec 15 11:31:30 2015
@@ -195,6 +195,7 @@ branch_txn_open_branch(svn_branch__txn_t
                        svn_branch__state_t **new_branch_p,
                        const char *branch_id,
                        int root_eid,
+                       svn_branch__rev_bid_eid_t *tree_ref,
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool)
 {
@@ -216,57 +217,39 @@ branch_txn_open_branch(svn_branch__txn_t
       APR_ARRAY_PUSH(txn->priv->branches, void *) = new_branch;
     }
 
-  if (new_branch_p)
-    *new_branch_p = new_branch;
-  return SVN_NO_ERROR;
-}
-
-/* An #svn_branch__txn_t method. */
-static svn_error_t *
-branch_txn_branch(svn_branch__txn_t *txn,
-                  svn_branch__state_t **new_branch_p,
-                  svn_branch__rev_bid_eid_t *from,
-                  const char *new_branch_id,
-                  apr_pool_t *result_pool,
-                  apr_pool_t *scratch_pool)
-{
-  svn_branch__state_t *new_branch;
-  svn_branch__state_t *from_branch;
-  svn_element__tree_t *from_subtree;
-
-  SVN_ERR(branch_in_rev_or_txn(&from_branch, from, txn, scratch_pool));
-  /* Source branch must exist */
-  if (! from_branch)
+  if (tree_ref)
     {
-      return svn_error_createf(SVN_BRANCH__ERR, NULL,
-                               _("Cannot branch from r%ld %s e%d: "
-                                 "branch does not exist"),
-                               from->rev, from->bid, from->eid);
-    }
+      svn_branch__state_t *from_branch;
+      svn_element__tree_t *tree;
 
-  SVN_ERR_ASSERT(from_branch->priv->is_flat);
+      SVN_ERR(branch_in_rev_or_txn(&from_branch, tree_ref, txn, scratch_pool));
+      /* Source branch must exist */
+      if (! from_branch)
+        {
+          return svn_error_createf(SVN_BRANCH__ERR, NULL,
+                                   _("Cannot branch from r%ld %s e%d: "
+                                     "branch does not exist"),
+                                   tree_ref->rev, tree_ref->bid, tree_ref->eid);
+        }
 
-  SVN_ERR(svn_branch__state_get_elements(from_branch, &from_subtree,
-                                         scratch_pool));
-  from_subtree = svn_element__tree_get_subtree_at_eid(from_subtree,
-                                                     from->eid,
-                                                     scratch_pool);
-  /* Source element must exist */
-  if (! from_subtree)
-    {
-      return svn_error_createf(SVN_BRANCH__ERR, NULL,
-                               _("Cannot branch from r%ld %s e%d: "
-                                 "element does not exist"),
-                               from->rev, from->bid, from->eid);
-    }
+      SVN_ERR_ASSERT(from_branch->priv->is_flat);
 
-  SVN_ERR(branch_txn_open_branch(txn, &new_branch, new_branch_id,
-                                 from->eid, scratch_pool, scratch_pool));
+      SVN_ERR(svn_branch__state_get_elements(from_branch, &tree,
+                                             scratch_pool));
+      tree = svn_element__tree_get_subtree_at_eid(tree, tree_ref->eid,
+                                                  scratch_pool);
+      /* Source element must exist */
+      if (! tree)
+        {
+          return svn_error_createf(SVN_BRANCH__ERR, NULL,
+                                   _("Cannot branch from r%ld %s e%d: "
+                                     "element does not exist"),
+                                   tree_ref->rev, tree_ref->bid, tree_ref->eid);
+        }
 
-  /* Populate the mapping from the 'from' source */
-  SVN_ERR(branch_instantiate_elements(new_branch, from_subtree,
-                                      scratch_pool));
-  new_branch->priv->is_flat = TRUE;
+      /* Populate the tree from the 'from' source */
+      SVN_ERR(branch_instantiate_elements(new_branch, tree, scratch_pool));
+    }
 
   if (new_branch_p)
     *new_branch_p = new_branch;
@@ -362,33 +345,19 @@ svn_branch__txn_open_branch(svn_branch__
                             svn_branch__state_t **new_branch_p,
                             const char *branch_id,
                             int root_eid,
+                            svn_branch__rev_bid_eid_t *tree_ref,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool)
 {
   SVN_ERR(txn->vtable->open_branch(txn,
                                    new_branch_p,
                                    branch_id,
-                                   root_eid, result_pool,
+                                   root_eid, tree_ref, result_pool,
                                    scratch_pool));
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_branch__txn_branch(svn_branch__txn_t *txn,
-                       svn_branch__state_t **new_branch_p,
-                       svn_branch__rev_bid_eid_t *from,
-                       const char *new_branch_id,
-                       apr_pool_t *result_pool,
-                       apr_pool_t *scratch_pool)
-{
-  SVN_ERR(txn->vtable->branch(txn,
-                              new_branch_p,
-                              from, new_branch_id, result_pool,
-                              scratch_pool));
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
 svn_branch__txn_finalize_eids(svn_branch__txn_t *txn,
                               apr_pool_t *scratch_pool)
 {
@@ -629,7 +598,6 @@ branch_txn_create(svn_branch__repos_t *r
     branch_txn_get_num_new_eids,
     branch_txn_new_eid,
     branch_txn_open_branch,
-    branch_txn_branch,
     branch_txn_finalize_eids,
     branch_txn_serialize,
     branch_txn_sequence_point,

Modified: subversion/trunk/subversion/libsvn_delta/branch_compat.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/branch_compat.c?rev=1720118&r1=1720117&r2=1720118&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/branch_compat.c (original)
+++ subversion/trunk/subversion/libsvn_delta/branch_compat.c Tue Dec 15 11:31:30 2015
@@ -1817,13 +1817,14 @@ compat_branch_txn_open_branch(svn_branch
                               svn_branch__state_t **new_branch_p,
                               const char *new_branch_id,
                               int root_eid,
+                              svn_branch__rev_bid_eid_t *tree_ref,
                               apr_pool_t *result_pool,
                               apr_pool_t *scratch_pool)
 {
   /* Just forwarding: nothing more is needed. */
   SVN_ERR(svn_branch__txn_open_branch(txn->priv->txn,
                                       new_branch_p,
-                                      new_branch_id, root_eid,
+                                      new_branch_id, root_eid, tree_ref,
                                       result_pool,
                                       scratch_pool));
   return SVN_NO_ERROR;
@@ -1831,29 +1832,6 @@ compat_branch_txn_open_branch(svn_branch
 
 /* An #svn_branch__txn_t method. */
 static svn_error_t *
-compat_branch_txn_branch(svn_branch__txn_t *txn,
-                         svn_branch__state_t **new_branch_p,
-                         svn_branch__rev_bid_eid_t *from,
-                         const char *new_branch_id,
-                         apr_pool_t *result_pool,
-                         apr_pool_t *scratch_pool)
-{
-  svn_branch__state_t *new_branch;
-
-  /* Just forwarding: nothing more is needed. */
-  SVN_ERR(svn_branch__txn_branch(txn->priv->txn,
-                                 &new_branch, from,
-                                 new_branch_id,
-                                 result_pool,
-                                 scratch_pool));
-
-  if (new_branch_p)
-    *new_branch_p = new_branch;
-  return SVN_NO_ERROR;
-}
-
-/* An #svn_branch__txn_t method. */
-static svn_error_t *
 compat_branch_txn_serialize(svn_branch__txn_t *txn,
                             svn_stream_t *stream,
                             apr_pool_t *scratch_pool)
@@ -1987,7 +1965,6 @@ svn_branch__compat_txn_from_delta_for_co
     compat_branch_txn_get_num_new_eids,
     compat_branch_txn_new_eid,
     compat_branch_txn_open_branch,
-    compat_branch_txn_branch,
     compat_branch_txn_finalize_eids,
     compat_branch_txn_serialize,
     compat_branch_txn_sequence_point,

Modified: subversion/trunk/subversion/libsvn_delta/branch_nested.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/branch_nested.c?rev=1720118&r1=1720117&r2=1720118&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/branch_nested.c (original)
+++ subversion/trunk/subversion/libsvn_delta/branch_nested.c Tue Dec 15 11:31:30 2015
@@ -302,8 +302,8 @@ svn_branch__instantiate_elements_r(svn_b
                                             scratch_pool);
         SVN_ERR(svn_branch__txn_open_branch(to_branch->txn, &new_branch,
                                             new_branch_id,
-                                            /*### reference_tree={empty},*/
                                             this_subtree->tree->root_eid,
+                                            NULL /*tree_ref*/,
                                             scratch_pool, scratch_pool));
         /*### SVN_ERR(svn_branch__state_set_history(new_branch, history,
                                               scratch_pool));*/
@@ -512,47 +512,33 @@ nested_branch_txn_open_branch(svn_branch
                               svn_branch__state_t **new_branch_p,
                               const char *new_branch_id,
                               int root_eid,
+                              svn_branch__rev_bid_eid_t *tree_ref,
                               apr_pool_t *result_pool,
                               apr_pool_t *scratch_pool)
 {
-  /* Just forwarding: nothing more is needed. */
+  svn_branch__state_t *new_branch;
+
   SVN_ERR(svn_branch__txn_open_branch(txn->priv->wrapped_txn,
-                                      new_branch_p,
-                                      new_branch_id, root_eid,
+                                      &new_branch,
+                                      new_branch_id, root_eid, tree_ref,
                                       result_pool,
                                       scratch_pool));
-  return SVN_NO_ERROR;
-}
-
-/* Implements nested branching.
- * An #svn_branch__txn_t method. */
-static svn_error_t *
-nested_branch_txn_branch(svn_branch__txn_t *txn,
-                         svn_branch__state_t **new_branch_p,
-                         svn_branch__rev_bid_eid_t *from,
-                         const char *new_branch_id,
-                         apr_pool_t *result_pool,
-                         apr_pool_t *scratch_pool)
-{
-  svn_branch__state_t *new_branch;
-  svn_branch__state_t *from_branch;
-  svn_branch__subtree_t *from_subtree;
-
-  SVN_ERR(svn_branch__txn_branch(txn->priv->wrapped_txn,
-                                 &new_branch, from,
-                                 new_branch_id,
-                                 result_pool,
-                                 scratch_pool));
 
   /* Recursively branch any nested branches */
-  /* (The way we're doing it here also redundantly re-instantiates all the
-     elements in NEW_BRANCH.) */
-  SVN_ERR(branch_in_rev_or_txn(&from_branch, from, txn->priv->wrapped_txn,
-                               scratch_pool));
-  SVN_ERR(svn_branch__get_subtree(from_branch, &from_subtree, from->eid,
-                                  scratch_pool));
-  SVN_ERR(svn_branch__instantiate_elements_r(new_branch, *from_subtree,
-                                             scratch_pool));
+  if (tree_ref)
+    {
+      svn_branch__state_t *from_branch;
+      svn_branch__subtree_t *from_subtree;
+
+      /* (The way we're doing it here also redundantly re-instantiates all the
+         elements in NEW_BRANCH.) */
+      SVN_ERR(branch_in_rev_or_txn(&from_branch, tree_ref,
+                                   txn->priv->wrapped_txn, scratch_pool));
+      SVN_ERR(svn_branch__get_subtree(from_branch, &from_subtree,
+                                      tree_ref->eid, scratch_pool));
+      SVN_ERR(svn_branch__instantiate_elements_r(new_branch, *from_subtree,
+                                                 scratch_pool));
+    }
 
   if (new_branch_p)
     *new_branch_p = new_branch;
@@ -655,7 +641,6 @@ svn_branch__nested_txn_create(svn_branch
     nested_branch_txn_get_num_new_eids,
     nested_branch_txn_new_eid,
     nested_branch_txn_open_branch,
-    nested_branch_txn_branch,
     nested_branch_txn_finalize_eids,
     nested_branch_txn_serialize,
     nested_branch_txn_sequence_point,

Modified: subversion/trunk/tools/dev/svnmover/merge3.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/dev/svnmover/merge3.c?rev=1720118&r1=1720117&r2=1720118&view=diff
==============================================================================
--- subversion/trunk/tools/dev/svnmover/merge3.c (original)
+++ subversion/trunk/tools/dev/svnmover/merge3.c Tue Dec 15 11:31:30 2015
@@ -899,8 +899,9 @@ merge_subbranch(svn_branch__txn_t *edit_
                                          scratch_pool);
       svn_branch__state_t *edit_subbranch;
 
-      SVN_ERR(svn_branch__txn_branch(edit_txn, &edit_subbranch, from,
-                                     new_branch_id, scratch_pool, scratch_pool));
+      SVN_ERR(svn_branch__txn_open_branch(edit_txn, &edit_subbranch,
+                                          new_branch_id, from->eid, from,
+                                          scratch_pool, scratch_pool));
 
       /* subbranch possibly changed in source => merge */
       SVN_ERR(branch_merge_subtree_r(edit_txn, edit_subbranch,
@@ -933,8 +934,9 @@ merge_subbranch(svn_branch__txn_t *edit_
                                          svn_branch__root_eid(src_subbranch),
                                          scratch_pool);
 
-      SVN_ERR(svn_branch__txn_branch(edit_txn, NULL /*new_branch_p*/, from,
-                                     new_branch_id, scratch_pool, scratch_pool));
+      SVN_ERR(svn_branch__txn_open_branch(edit_txn, NULL /*new_branch_p*/,
+                                          new_branch_id, from->eid, from,
+                                          scratch_pool, scratch_pool));
     }
   else if (subbr_tgt)  /* added on target branch */
     {
@@ -948,8 +950,9 @@ merge_subbranch(svn_branch__txn_t *edit_
                                          svn_branch__root_eid(tgt_subbranch),
                                          scratch_pool);
 
-      SVN_ERR(svn_branch__txn_branch(edit_txn, NULL /*new_branch_p*/, from,
-                                     new_branch_id, scratch_pool, scratch_pool));
+      SVN_ERR(svn_branch__txn_open_branch(edit_txn, NULL /*new_branch_p*/,
+                                          new_branch_id, from->eid, from,
+                                          scratch_pool, scratch_pool));
     }
   else if (subbr_yca)  /* double delete */
     {

Modified: subversion/trunk/tools/dev/svnmover/svnmover.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/dev/svnmover/svnmover.c?rev=1720118&r1=1720117&r2=1720118&view=diff
==============================================================================
--- subversion/trunk/tools/dev/svnmover/svnmover.c (original)
+++ subversion/trunk/tools/dev/svnmover/svnmover.c Tue Dec 15 11:31:30 2015
@@ -917,6 +917,7 @@ svn_branch__replay(svn_branch__txn_t *ed
               SVN_ERR(svn_branch__txn_open_branch(edit_txn, &edit_subbranch,
                                                   new_branch_id,
                                                   svn_branch__root_eid(right_subbranch),
+                                                  NULL /*tree_ref*/,
                                                   scratch_pool, scratch_pool));
             }
 
@@ -1095,6 +1096,7 @@ update_wc_base_r(svnmover_wc_t *wc,
                                                   &base_subbranch,
                                                   new_branch_id,
                                                   svn_branch__root_eid(work_subbranch),
+                                                  NULL /*tree_ref*/,
                                                   scratch_pool, scratch_pool));
               SVN_ERR(svn_branch__state_get_history(
                         work_subbranch, &history, scratch_pool));
@@ -2634,7 +2636,7 @@ do_mkbranch(const char **new_branch_id_p
                                       scratch_pool);
   SVN_ERR(svn_branch__txn_open_branch(txn, &new_branch,
                                       new_branch_id, new_inner_eid,
-                                      /*### reference_tree={empty},*/
+                                      NULL /*tree_ref*/,
                                       scratch_pool, scratch_pool));
   SVN_ERR(svn_branch__state_alter_one(new_branch, new_inner_eid,
                                       -1, "", payload, scratch_pool));
@@ -2684,9 +2686,9 @@ do_branch(svn_branch__state_t **new_bran
 
   new_branch_id = svn_branch__id_nest(to_outer_branch_id, to_outer_eid,
                                       scratch_pool);
-  SVN_ERR(svn_branch__txn_branch(txn, &new_branch,
-                                 from, new_branch_id,
-                                 result_pool, scratch_pool));
+  SVN_ERR(svn_branch__txn_open_branch(txn, &new_branch,
+                                      new_branch_id, from->eid, from,
+                                      result_pool, scratch_pool));
   history = svn_branch__history_create_empty(scratch_pool);
   SVN_ERR(svn_branch__history_add_parent(history, from->rev, from->bid,
                                          scratch_pool));
@@ -2719,9 +2721,9 @@ do_topbranch(svn_branch__state_t **new_b
   SVN_ERR(svn_branch__txn_new_eid(txn, &outer_eid, scratch_pool));
   new_branch_id = svn_branch__id_nest(NULL /*outer_branch*/, outer_eid,
                                       scratch_pool);
-  SVN_ERR(svn_branch__txn_branch(txn, &new_branch,
-                                 from, new_branch_id,
-                                 result_pool, scratch_pool));
+  SVN_ERR(svn_branch__txn_open_branch(txn, &new_branch,
+                                      new_branch_id, from->eid, from,
+                                      result_pool, scratch_pool));
 
   svnmover_notify_v("A+   (branch %s)",
                     new_branch->bid);



Mime
View raw message