The following commit has been merged in the master branch:
commit 358dc84c4537815fab85beca29093d74c9b979cd
Author: Guillem Jover <[email protected]>
Date:   Tue Jan 25 16:58:57 2011 +0100

    Update deppossi->ed to point to a pkgset instead of a pkginfo
    
    It represents only the package name of the dependency. Later deppossi
    will grow an architecture parameter that will allow us to transform
    that pkgset into the correct pkginfo (depending on the context).
    
    Note that this transformation depends on the dependency type
    (possi->up->dep_type) and as such it won't be done at parsing time
    but rather every time that we need to analyze a specific dependency.
    
    [[email protected]: (Sponsored-by: Linaro Limited)
     - Update code for new location of depended struct.
     - Update call sites for pkg_db_find() returning pkginfo. ]
    
    Signed-off-by: Guillem Jover <[email protected]>

diff --git a/dselect/pkgdepcon.cc b/dselect/pkgdepcon.cc
index c998dd5..8170002 100644
--- a/dselect/pkgdepcon.cc
+++ b/dselect/pkgdepcon.cc
@@ -99,7 +99,7 @@ int packagelist::resolvesuggest() {
            depends;
            depends= depends->next) {
         if (depends->type != dep_provides) continue;
-        changemade= checkdependers(depends->list->ed,changemade);
+        changemade = checkdependers(&depends->list->ed->pkg, changemade);
       }
       debug(dbg_depcon, "packagelist[%p]::resolvesuggest() loop[%i] %s / -> 
%d",
             this, index, table[index]->pkg->name, changemade);
@@ -269,9 +269,11 @@ int packagelist::resolvedepcon(dependency *depends) {
            possi;
            possi= possi->next) {
         foundany= 0;
-        if (possi->ed->clientdata) foundany= 1;
-        if (dep_update_best_to_change_stop(best, possi->ed)) goto mustdeselect;
-        for (provider = possi->ed->set->depended.available;
+        if (possi->ed->pkg.clientdata)
+          foundany = 1;
+        if (dep_update_best_to_change_stop(best, &possi->ed->pkg))
+          goto mustdeselect;
+        for (provider = possi->ed->depended.available;
              provider;
              provider = provider->rev_next) {
           if (provider->up->type != dep_provides) continue;
@@ -333,10 +335,12 @@ int packagelist::resolvedepcon(dependency *depends) {
           "packagelist[%p]::resolvedepcon([%p]): conflict satisfied - ouch",
           this, depends);
 
-    if (depends->up != depends->list->ed) {
-      r= deselect_one_of(depends->up, depends->list->ed, depends);  if (r) 
return r;
+    if (depends->up->set != depends->list->ed) {
+      r = deselect_one_of(depends->up, &depends->list->ed->pkg, depends);
+      if (r)
+        return r;
     }
-    for (provider = depends->list->ed->set->depended.available;
+    for (provider = depends->list->ed->depended.available;
          provider;
          provider = provider->rev_next) {
       if (provider->up->type != dep_provides) continue;
@@ -362,31 +366,31 @@ packagelist::deppossatisfied(deppossi *possi, 
perpackagestate **fixbyupgrade)
   int would;
   pkginfo::pkgwant want= pkginfo::want_purge;
 
-  if (possi->ed->clientdata) {
-    want= possi->ed->clientdata->selected;
-    would= would_like_to_install(want,possi->ed);
+  if (possi->ed->pkg.clientdata) {
+    want = possi->ed->pkg.clientdata->selected;
+    would = would_like_to_install(want, &possi->ed->pkg);
   } else {
     would= 0;
   }
 
   if ((possi->up->type == dep_conflicts || possi->up->type == dep_breaks)
-      ? possi->up->up != possi->ed && would != 0
+      ? possi->up->up->set != possi->ed && would != 0
       : would > 0) {
     // If it's to be installed or left installed, then either it's of
     // the right version, and therefore OK, or a version must have
     // been specified, in which case we don't need to look at the rest
     // anyway.
-    if (useavailable(possi->ed)) {
+    if (useavailable(&possi->ed->pkg)) {
       assert(want == pkginfo::want_install);
-      return versionsatisfied(&possi->ed->available,possi);
+      return versionsatisfied(&possi->ed->pkg.available, possi);
     } else {
-      if (versionsatisfied(&possi->ed->installed, possi))
+      if (versionsatisfied(&possi->ed->pkg.installed, possi))
         return true;
       if (want == pkginfo::want_hold && fixbyupgrade && !*fixbyupgrade &&
-          versionsatisfied(&possi->ed->available,possi) &&
-          versioncompare(&possi->ed->available.version,
-                         &possi->ed->installed.version) > 1)
-        *fixbyupgrade= possi->ed->clientdata;
+          versionsatisfied(&possi->ed->pkg.available, possi) &&
+          versioncompare(&possi->ed->pkg.available.version,
+                         &possi->ed->pkg.installed.version) > 1)
+        *fixbyupgrade = possi->ed->pkg.clientdata;
       return false;
     }
   }
@@ -394,7 +398,7 @@ packagelist::deppossatisfied(deppossi *possi, 
perpackagestate **fixbyupgrade)
     return false;
   deppossi *provider;
 
-  for (provider = possi->ed->set->depended.installed;
+  for (provider = possi->ed->depended.installed;
        provider;
        provider = provider->rev_next) {
     if (provider->up->type == dep_provides &&
@@ -404,7 +408,7 @@ packagelist::deppossatisfied(deppossi *possi, 
perpackagestate **fixbyupgrade)
                               provider->up->up))
       return true;
   }
-  for (provider = possi->ed->set->depended.available;
+  for (provider = possi->ed->depended.available;
        provider;
        provider = provider->rev_next) {
     if (provider->up->type != dep_provides ||
diff --git a/dselect/pkgsublist.cc b/dselect/pkgsublist.cc
index 4ad4216..c7175f7 100644
--- a/dselect/pkgsublist.cc
+++ b/dselect/pkgsublist.cc
@@ -143,12 +143,12 @@ packagelist::add(dependency *depends, showpriority 
displayimportance)
   info('\n');
   add(depends->up,info.string(),displayimportance);
   for (possi=depends->list; possi; possi=possi->next) {
-    add(possi->ed,info.string(),displayimportance);
+    add(&possi->ed->pkg, info.string(), displayimportance);
     if (possi->verrel == dvr_none && depends->type != dep_provides) {
       // providers aren't relevant if a version was specified, or
       // if we're looking at a provider relationship already
       deppossi *provider;
-      for (provider = possi->ed->set->depended.available;
+      for (provider = possi->ed->depended.available;
            provider;
            provider = provider->rev_next) {
         if (provider->up->type != dep_provides) continue;
diff --git a/lib/dpkg/dpkg-db.h b/lib/dpkg/dpkg-db.h
index 6a13c68..914304f 100644
--- a/lib/dpkg/dpkg-db.h
+++ b/lib/dpkg/dpkg-db.h
@@ -70,7 +70,7 @@ struct dependency {
 
 struct deppossi {
   struct dependency *up;
-  struct pkginfo *ed;
+  struct pkgset *ed;
   struct deppossi *next, *rev_next, *rev_prev;
   struct versionrevision version;
   enum depverrel verrel;
diff --git a/lib/dpkg/fields.c b/lib/dpkg/fields.c
index ffb24b7..b329cbc 100644
--- a/lib/dpkg/fields.c
+++ b/lib/dpkg/fields.c
@@ -404,7 +404,7 @@ f_dependency(struct pkginfo *pigp, struct pkgbin *pifp,
                     fip->name, depname.buf, emsg);
       dop= nfmalloc(sizeof(struct deppossi));
       dop->up= dyp;
-      dop->ed = pkg_db_find(depname.buf);
+      dop->ed = pkg_db_find(depname.buf)->set;
       dop->next= NULL; *ldopp= dop; ldopp= &dop->next;
 
       /* Don't link this (which is after all only ‘newpig’ from
diff --git a/lib/dpkg/parse.c b/lib/dpkg/parse.c
index a97c848..743c9fb 100644
--- a/lib/dpkg/parse.c
+++ b/lib/dpkg/parse.c
@@ -619,9 +619,9 @@ void copy_dependency_links(struct pkginfo *pkg,
         dop->rev_prev->rev_next = dop->rev_next;
       else
         if (available)
-          dop->ed->set->depended.available = dop->rev_next;
+          dop->ed->depended.available = dop->rev_next;
         else
-          dop->ed->set->depended.installed = dop->rev_next;
+          dop->ed->depended.installed = dop->rev_next;
       if (dop->rev_next)
         dop->rev_next->rev_prev = dop->rev_prev;
     }
@@ -632,8 +632,8 @@ void copy_dependency_links(struct pkginfo *pkg,
   for (dyp= newdepends; dyp; dyp= dyp->next) {
     dyp->up= pkg;
     for (dop= dyp->list; dop; dop= dop->next) {
-      revdeps = available ? &dop->ed->set->depended.available :
-                            &dop->ed->set->depended.installed;
+      revdeps = available ? &dop->ed->depended.available :
+                            &dop->ed->depended.installed;
       dop->rev_next = *revdeps;
       dop->rev_prev = NULL;
       if (*revdeps)
diff --git a/src/archives.c b/src/archives.c
index 91e2f30..0bc6e74 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -218,7 +218,8 @@ does_replace(struct pkginfo *newpigp, struct pkgbin 
*newpifp,
   debug(dbg_depcon,"does_replace new=%s old=%s (%s)",newpigp->name,
         oldpigp->name, versiondescribe(&oldpifp->version, vdew_always));
   for (dep= newpifp->depends; dep; dep= dep->next) {
-    if (dep->type != dep_replaces || dep->list->ed != oldpigp) continue;
+    if (dep->type != dep_replaces || dep->list->ed != oldpigp->set)
+      continue;
     debug(dbg_depcondetail,"does_replace ... found old, version %s",
           versiondescribe(&dep->list->version,vdew_always));
     if (!versionsatisfied(oldpifp, dep->list))
@@ -1140,7 +1141,7 @@ void check_conflict(struct dependency *dep, struct 
pkginfo *pkg,
                providecheck;
                providecheck= providecheck->next) {
             if (providecheck->type != dep_provides) continue;
-            for (pdep = providecheck->list->ed->set->depended.installed;
+            for (pdep = providecheck->list->ed->depended.installed;
                  pdep;
                  pdep = pdep->rev_next) {
               if (pdep->up->type != dep_depends && pdep->up->type != 
dep_predepends)
diff --git a/src/depcon.c b/src/depcon.c
index ee9db26..3293142 100644
--- a/src/depcon.c
+++ b/src/depcon.c
@@ -128,10 +128,10 @@ findbreakcyclerecursive(struct pkginfo *pkg, struct 
cyclesofarlink *sofar)
       /* Don't find the same cycles again. */
       if (possi->cyclebreak) continue;
       thislink.possi= possi;
-      if (foundcyclebroken(&thislink, sofar, possi->ed,possi))
+      if (foundcyclebroken(&thislink, sofar, &possi->ed->pkg, possi))
         return true;
       /* Right, now we try all the providers ... */
-      for (providelink = possi->ed->set->depended.installed;
+      for (providelink = possi->ed->depended.installed;
            providelink;
            providelink = providelink->rev_next) {
         if (providelink->up->type != dep_provides) continue;
@@ -291,7 +291,7 @@ depisok(struct dependency *dep, struct varbuf *whynot,
      * can return ‘false’. */
 
     for (possi= dep->list; possi; possi= possi->next) {
-      switch (possi->ed->clientdata->istobe) {
+      switch (possi->ed->pkg.clientdata->istobe) {
       case itb_remove:
         sprintf(linebuf,_("  %.250s is to be removed.\n"),possi->ed->name);
         break;
@@ -299,21 +299,21 @@ depisok(struct dependency *dep, struct varbuf *whynot,
         sprintf(linebuf,_("  %.250s is to be 
deconfigured.\n"),possi->ed->name);
         break;
       case itb_installnew:
-        if (versionsatisfied(&possi->ed->available, possi))
+        if (versionsatisfied(&possi->ed->pkg.available, possi))
           return true;
         sprintf(linebuf,_("  %.250s is to be installed, but is version 
%.250s.\n"),
                 possi->ed->name,
-                versiondescribe(&possi->ed->available.version,vdew_nonambig));
+                versiondescribe(&possi->ed->pkg.available.version, 
vdew_nonambig));
         break;
       case itb_normal: case itb_preinstall:
-        switch (possi->ed->status) {
+        switch (possi->ed->pkg.status) {
         case stat_installed:
         case stat_triggerspending:
-          if (versionsatisfied(&possi->ed->installed, possi))
+          if (versionsatisfied(&possi->ed->pkg.installed, possi))
             return true;
           sprintf(linebuf,_("  %.250s is installed, but is version %.250s.\n"),
                   possi->ed->name,
-                  
versiondescribe(&possi->ed->installed.version,vdew_nonambig));
+                  versiondescribe(&possi->ed->pkg.installed.version, 
vdew_nonambig));
           break;
         case stat_notinstalled:
           /* Don't say anything about this yet - it might be a virtual package.
@@ -322,27 +322,28 @@ depisok(struct dependency *dep, struct varbuf *whynot,
           *linebuf = '\0';
           break;
         case stat_triggersawaited:
-            if (canfixbytrigaw && versionsatisfied(&possi->ed->installed, 
possi))
-              *canfixbytrigaw = possi->ed;
+            if (canfixbytrigaw &&
+                versionsatisfied(&possi->ed->pkg.installed, possi))
+              *canfixbytrigaw = &possi->ed->pkg;
             /* Fall through to have a chance to return OK due to
              * allowunconfigd and to fill the explanation */
         case stat_unpacked:
         case stat_halfconfigured:
           if (allowunconfigd) {
-            if (!informativeversion(&possi->ed->configversion)) {
+            if (!informativeversion(&possi->ed->pkg.configversion)) {
               sprintf(linebuf, _("  %.250s is unpacked, but has never been 
configured.\n"),
                       possi->ed->name);
               break;
-            } else if (!versionsatisfied(&possi->ed->installed, possi)) {
+            } else if (!versionsatisfied(&possi->ed->pkg.installed, possi)) {
               sprintf(linebuf, _("  %.250s is unpacked, but is version 
%.250s.\n"),
                       possi->ed->name,
-                      versiondescribe(&possi->ed->installed.version, 
vdew_nonambig));
+                      versiondescribe(&possi->ed->pkg.installed.version, 
vdew_nonambig));
               break;
-            } else if (!versionsatisfied3(&possi->ed->configversion,
+            } else if (!versionsatisfied3(&possi->ed->pkg.configversion,
                                           &possi->version,possi->verrel)) {
               sprintf(linebuf, _("  %.250s latest configured version is 
%.250s.\n"),
                       possi->ed->name,
-                      
versiondescribe(&possi->ed->configversion,vdew_nonambig));
+                      versiondescribe(&possi->ed->pkg.configversion, 
vdew_nonambig));
               break;
             } else {
               return true;
@@ -351,19 +352,19 @@ depisok(struct dependency *dep, struct varbuf *whynot,
           /* Fall through. */
         default:
           sprintf(linebuf, _("  %.250s is %s.\n"),
-                  possi->ed->name, gettext(statusstrings[possi->ed->status]));
+                  possi->ed->name, 
gettext(statusstrings[possi->ed->pkg.status]));
           break;
         }
         break;
       default:
-        internerr("unknown istobe depended '%d'", 
possi->ed->clientdata->istobe);
+        internerr("unknown istobe depended '%d'", 
possi->ed->pkg.clientdata->istobe);
       }
       varbuf_add_str(whynot, linebuf);
 
       /* If there was no version specified we try looking for Providers. */
       if (possi->verrel == dvr_none) {
         /* See if the package we're about to install Provides it. */
-        for (provider = possi->ed->set->depended.available;
+        for (provider = possi->ed->depended.available;
              provider;
              provider = provider->rev_next) {
           if (provider->up->type != dep_provides) continue;
@@ -372,7 +373,7 @@ depisok(struct dependency *dep, struct varbuf *whynot,
         }
 
         /* Now look at the packages already on the system. */
-        for (provider = possi->ed->set->depended.installed;
+        for (provider = possi->ed->depended.installed;
              provider;
              provider = provider->rev_next) {
           if (provider->up->type != dep_provides) continue;
@@ -429,32 +430,33 @@ depisok(struct dependency *dep, struct varbuf *whynot,
     possi= dep->list;
     nconflicts= 0;
 
-    if (possi->ed != possi->up->up) {
+    if (possi->ed != possi->up->up->set) {
       /* If the package conflicts with or breaks itself it must mean
        * other packages which provide the same virtual name. We
        * therefore don't look at the real package and go on to the
        * virtual ones. */
 
-      switch (possi->ed->clientdata->istobe) {
+      switch (possi->ed->pkg.clientdata->istobe) {
       case itb_remove:
         break;
       case itb_installnew:
-        if (!versionsatisfied(&possi->ed->available, possi)) break;
+        if (!versionsatisfied(&possi->ed->pkg.available, possi))
+          break;
         sprintf(linebuf, _("  %.250s (version %.250s) is to be installed.\n"),
                 possi->ed->name,
-                versiondescribe(&possi->ed->available.version,vdew_nonambig));
+                versiondescribe(&possi->ed->pkg.available.version, 
vdew_nonambig));
         varbuf_add_str(whynot, linebuf);
         if (!canfixbyremove)
           return false;
         nconflicts++;
-        *canfixbyremove= possi->ed;
+        *canfixbyremove = &possi->ed->pkg;
         break;
       case itb_deconfigure:
         if (dep->type == dep_breaks)
           break; /* Already deconfiguring this. */
         /* Fall through. */
       case itb_normal: case itb_preinstall:
-        switch (possi->ed->status) {
+        switch (possi->ed->pkg.status) {
         case stat_notinstalled: case stat_configfiles:
           break;
         case stat_halfinstalled: case stat_unpacked:
@@ -464,28 +466,29 @@ depisok(struct dependency *dep, struct varbuf *whynot,
         case stat_installed:
         case stat_triggerspending:
         case stat_triggersawaited:
-          if (!versionsatisfied(&possi->ed->installed, possi)) break;
+          if (!versionsatisfied(&possi->ed->pkg.installed, possi))
+            break;
           sprintf(linebuf, _("  %.250s (version %.250s) is present and %s.\n"),
                   possi->ed->name,
-                  versiondescribe(&possi->ed->installed.version,vdew_nonambig),
-                  gettext(statusstrings[possi->ed->status]));
+                  versiondescribe(&possi->ed->pkg.installed.version, 
vdew_nonambig),
+                  gettext(statusstrings[possi->ed->pkg.status]));
           varbuf_add_str(whynot, linebuf);
           if (!canfixbyremove)
             return false;
           nconflicts++;
-          *canfixbyremove= possi->ed;
+          *canfixbyremove = &possi->ed->pkg;
         }
         break;
       default:
         internerr("unknown istobe conflict '%d'",
-                  possi->ed->clientdata->istobe);
+                  possi->ed->pkg.clientdata->istobe);
       }
     }
 
     /* If there was no version specified we try looking for Providers. */
     if (possi->verrel == dvr_none) {
       /* See if the package we're about to install Provides it. */
-      for (provider = possi->ed->set->depended.available;
+      for (provider = possi->ed->depended.available;
            provider;
            provider = provider->rev_next) {
         if (provider->up->type != dep_provides) continue;
@@ -502,7 +505,7 @@ depisok(struct dependency *dep, struct varbuf *whynot,
       }
 
       /* Now look at the packages already on the system. */
-      for (provider = possi->ed->set->depended.installed;
+      for (provider = possi->ed->depended.installed;
            provider;
            provider = provider->rev_next) {
         if (provider->up->type != dep_provides) continue;
diff --git a/src/enquiry.c b/src/enquiry.c
index d692e1e..f6e1331 100644
--- a/src/enquiry.c
+++ b/src/enquiry.c
@@ -413,12 +413,12 @@ predeppackage(const char *const *argv)
     for (possi = dep->list, pkg = NULL;
          !pkg && possi;
          possi=possi->next) {
-      trypkg= possi->ed;
+      trypkg = &possi->ed->pkg;
       if (trypkg->files && versionsatisfied(&trypkg->available,possi)) {
         if (trypkg->clientdata->istobe == itb_normal) { pkg= trypkg; break; }
       }
       if (possi->verrel != dvr_none) continue;
-      for (provider = possi->ed->set->depended.available;
+      for (provider = possi->ed->depended.available;
            !pkg && provider;
            provider=provider->next) {
         if (provider->up->type != dep_provides) continue;
diff --git a/src/help.c b/src/help.c
index 9208410..978ead0 100644
--- a/src/help.c
+++ b/src/help.c
@@ -156,7 +156,7 @@ bool
 force_depends(struct deppossi *possi)
 {
   return fc_depends ||
-         ignore_depends(possi->ed) ||
+         ignore_depends(&possi->ed->pkg) ||
          ignore_depends(possi->up->up);
 }
 
@@ -164,7 +164,7 @@ bool
 force_breaks(struct deppossi *possi)
 {
   return fc_breaks ||
-         ignore_depends(possi->ed) ||
+         ignore_depends(&possi->ed->pkg) ||
          ignore_depends(possi->up->up);
 }
 
diff --git a/src/packages.c b/src/packages.c
index f7c3b36..1bd5534 100644
--- a/src/packages.c
+++ b/src/packages.c
@@ -515,7 +515,7 @@ breakses_ok(struct pkginfo *pkg, struct varbuf *aemsgs)
 
   for (dep= pkg->installed.depends; dep; dep= dep->next) {
     if (dep->type != dep_provides) continue;
-    virtbroken= dep->list->ed;
+    virtbroken = &dep->list->ed->pkg;
     debug(dbg_depcondetail, "     checking virtbroken %s", virtbroken->name);
     breaks_check_target(aemsgs, &ok, pkg, virtbroken, virtbroken);
   }
@@ -561,19 +561,20 @@ dependencies_ok(struct pkginfo *pkg, struct pkginfo 
*removing,
         found = found_ok;
         break;
       }
-      thisf = deppossi_ok_found(possi->ed, pkg, removing, NULL,
+      thisf = deppossi_ok_found(&possi->ed->pkg, pkg, removing, NULL,
                                 &possfixbytrig,
                                &matched,possi,&interestingwarnings,&oemsgs);
       if (thisf > found) found= thisf;
       if (found != found_ok && possi->verrel == dvr_none) {
-        for (provider = possi->ed->set->depended.installed;
+        for (provider = possi->ed->depended.installed;
              found != found_ok && provider;
              provider = provider->rev_next) {
           if (provider->up->type != dep_provides)
             continue;
           debug(dbg_depcondetail, "     checking provider %s",
                 provider->up->up->name);
-          thisf = deppossi_ok_found(provider->up->up, pkg, removing, possi->ed,
+          thisf = deppossi_ok_found(provider->up->up, pkg, removing,
+                                    &possi->ed->pkg,
                                     &possfixbytrig, &matched, NULL,
                                     &interestingwarnings, &oemsgs);
           if (thisf > found)
diff --git a/src/processarc.c b/src/processarc.c
index 32f762a..9d1ca6a 100644
--- a/src/processarc.c
+++ b/src/processarc.c
@@ -532,7 +532,7 @@ void process_archive(const char *filename) {
       break;
     case dep_provides:
       /* Look for things that conflict with what we provide. */
-      for (psearch = dsearch->list->ed->set->depended.installed;
+      for (psearch = dsearch->list->ed->depended.installed;
            psearch;
            psearch = psearch->rev_next) {
         if (psearch->up->type != dep_conflicts)
@@ -1216,7 +1216,7 @@ void process_archive(const char *filename) {
            providecheck;
            providecheck= providecheck->next) {
         if (providecheck->type != dep_provides) continue;
-        for (pdep = providecheck->list->ed->set->depended.installed;
+        for (pdep = providecheck->list->ed->depended.installed;
              pdep;
              pdep = pdep->rev_next) {
           if (pdep->up->type != dep_depends && pdep->up->type != 
dep_predepends &&
diff --git a/src/remove.c b/src/remove.c
index a8e062f..3e56e76 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -113,7 +113,7 @@ void deferred_remove(struct pkginfo *pkg) {
   for (dep= pkg->installed.depends; dep; dep= dep->next) {
     if (dep->type != dep_provides) continue;
     debug(dbg_depcon,"checking virtual package `%s'",dep->list->ed->name);
-    checkforremoval(pkg,dep->list->ed,&rok,&raemsgs);
+    checkforremoval(pkg, &dep->list->ed->pkg, &rok, &raemsgs);
   }
 
   if (rok == 1) {

-- 
dpkg's main repository


-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to