]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
idnode: add generic mapping interface
authorJaroslav Kysela <perex@perex.cz>
Mon, 15 Jun 2015 19:57:18 +0000 (21:57 +0200)
committerJaroslav Kysela <perex@perex.cz>
Mon, 15 Jun 2015 19:57:21 +0000 (21:57 +0200)
- channel-service mapping rewritten
- channel-chtag mapping rewritten

17 files changed:
src/bouquet.c
src/channels.c
src/channels.h
src/dvr/dvr_autorec.c
src/epg.c
src/epggrab/module/eit.c
src/epggrab/module/opentv.c
src/htsp_server.c
src/idnode.c
src/idnode.h
src/input/mpegts/mpegts_mux.c
src/input/mpegts/mpegts_network.c
src/service.c
src/service.h
src/service_mapper.c
src/service_mapper.h
src/webui/webui.c

index ad846d9929edd1c784880eb1551cb04a37dce457..a78d4cc8658a064d490e3440bb3c2d284a8c93da 100644 (file)
@@ -224,7 +224,7 @@ static void
 bouquet_map_channel(bouquet_t *bq, service_t *t)
 {
   channel_t *ch = NULL;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
 
   if (!t->s_enabled)
     return;
@@ -236,15 +236,18 @@ bouquet_map_channel(bouquet_t *bq, service_t *t)
     return;
   if (!bq->bq_mapnoname && noname(service_get_channel_name(t)))
     return;
-  LIST_FOREACH(csm, &t->s_channels, csm_svc_link)
-    if (csm->csm_chn->ch_bouquet == bq)
+  LIST_FOREACH(ilm, &t->s_channels, ilm_in1_link)
+    if (((channel_t *)ilm->ilm_in2)->ch_bouquet == bq)
       break;
-  if (!csm)
+  if (!ilm)
     ch = service_mapper_process(t, bq);
   else
-    ch = csm->csm_chn;
+    ch = (channel_t *)ilm->ilm_in2;
   if (ch && bq->bq_chtag)
-    channel_tag_map(ch, bouquet_tag(bq, 1));
+    if (channel_tag_map(bouquet_tag(bq, 1), ch, ch)) {
+      idnode_notify_changed(&ch->ch_id);
+      channel_save(ch);
+    }
 }
 
 /*
@@ -254,7 +257,7 @@ void
 bouquet_add_service(bouquet_t *bq, service_t *s, uint64_t lcn, uint32_t tag)
 {
   service_lcn_t *tl;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
 
   lock_assert(&global_lock);
 
@@ -282,8 +285,8 @@ bouquet_add_service(bouquet_t *bq, service_t *s, uint64_t lcn, uint32_t tag)
   }
   if (lcn != tl->sl_lcn) {
     tl->sl_lcn = lcn;
-    LIST_FOREACH(csm, &s->s_channels, csm_svc_link)
-      idnode_notify_changed(&csm->csm_chn->ch_id);
+    LIST_FOREACH(ilm, &s->s_channels, ilm_in1_link)
+      idnode_notify_changed(ilm->ilm_in2);
   }
   tl->sl_seen = 1;
 
@@ -307,18 +310,18 @@ bouquet_add_service(bouquet_t *bq, service_t *s, uint64_t lcn, uint32_t tag)
 static void
 bouquet_unmap_channel(bouquet_t *bq, service_t *t)
 {
-  channel_service_mapping_t *csm, *csm_next;
+  idnode_list_mapping_t *ilm, *ilm_next;
 
-  csm = LIST_FIRST(&t->s_channels);
-  while (csm) {
-    csm_next = LIST_NEXT(csm, csm_svc_link);
-    if (csm->csm_chn->ch_bouquet == bq) {
+  ilm = LIST_FIRST(&t->s_channels);
+  while (ilm) {
+    ilm_next = LIST_NEXT(ilm, ilm_in1_link);
+    if (((channel_t *)ilm->ilm_in2)->ch_bouquet == bq) {
       tvhinfo("bouquet", "%s / %s: unmapped from %s",
-              channel_get_name(csm->csm_chn), t->s_nicename,
+              channel_get_name((channel_t *)ilm->ilm_in2), t->s_nicename,
               bq->bq_name ?: "<unknown>");
-      channel_delete(csm->csm_chn, 1);
+      channel_delete((channel_t *)ilm->ilm_in2, 1);
     }
-    csm = csm_next;
+    ilm = ilm_next;
   }
 }
 
@@ -448,15 +451,15 @@ bouquet_map_to_channels(bouquet_t *bq)
 void
 bouquet_notify_channels(bouquet_t *bq)
 {
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
   service_t *t;
   size_t z;
 
   for (z = 0; z < bq->bq_services->is_count; z++) {
     t = (service_t *)bq->bq_services->is_array[z];
-    LIST_FOREACH(csm, &t->s_channels, csm_svc_link)
-      if (csm->csm_chn->ch_bouquet == bq)
-        idnode_notify_changed(&csm->csm_chn->ch_id);
+    LIST_FOREACH(ilm, &t->s_channels, ilm_in1_link)
+      if (((channel_t *)ilm->ilm_in2)->ch_bouquet == bq)
+        idnode_notify_changed(ilm->ilm_in2);
   }
 }
 
@@ -661,7 +664,7 @@ bouquet_class_chtag_notify ( void *obj )
 {
   bouquet_t *bq = obj;
   service_t *t;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
   channel_tag_t *ct;
   size_t z;
 
@@ -673,11 +676,11 @@ bouquet_class_chtag_notify ( void *obj )
       return;
     for (z = 0; z < bq->bq_services->is_count; z++) {
       t = (service_t *)bq->bq_services->is_array[z];
-      LIST_FOREACH(csm, &t->s_channels, csm_svc_link)
-        if (csm->csm_chn->ch_bouquet == bq)
+      LIST_FOREACH(ilm, &t->s_channels, ilm_in1_link)
+        if (((channel_t *)ilm->ilm_in2)->ch_bouquet == bq)
           break;
-      if (csm)
-        channel_tag_unmap(csm->csm_chn, ct);
+      if (ilm)
+        channel_tag_unmap((channel_t *)ilm->ilm_in2, ct);
     }
   } else {
     bouquet_map_to_channels(bq);
index fddad4216f604f4cec3e8ca7846d4fa263638bf9..8ad4db99b9d2625eec8c6cf8c00c1a7fd5988ced 100644 (file)
@@ -53,13 +53,7 @@ struct channel_tag_queue channel_tags;
 
 static void channel_tag_init ( void );
 static void channel_tag_done ( void );
-static void channel_tag_mapping_destroy(channel_tag_mapping_t *ctm, 
-                                       int flags);
-static void channel_tag_destroy(channel_tag_t *ct, int delconf);
-
-
-#define CTM_DESTROY_UPDATE_TAG     0x1
-#define CTM_DESTROY_UPDATE_CHANNEL 0x2
+static void channel_tag_mapping_destroy(idnode_list_mapping_t *ilm, void *origin);
 
 static int
 ch_id_cmp ( channel_t *a, channel_t *b )
@@ -86,37 +80,24 @@ channel_class_delete ( idnode_t *self )
 static const void *
 channel_class_services_get ( void *obj )
 {
-  htsmsg_t *l = htsmsg_create_list();
   channel_t *ch = obj;
-  channel_service_mapping_t *csm;
-
-  /* Add all */
-  LIST_FOREACH(csm, &ch->ch_services, csm_chn_link)
-    htsmsg_add_str(l, NULL, idnode_uuid_as_str(&csm->csm_svc->s_id));
-
-  return l;
+  return idnode_list_get2(&ch->ch_services);
 }
 
 static char *
 channel_class_services_rend ( void *obj )
 {
-  char *str;
-  htsmsg_t   *l = htsmsg_create_list();
   channel_t *ch = obj;
-  channel_service_mapping_t  *csm;
-
-  LIST_FOREACH(csm, &ch->ch_services, csm_chn_link)
-    htsmsg_add_str(l, NULL, idnode_get_title(&csm->csm_svc->s_id) ?: "");
-
-  str = htsmsg_list_2_csv(l);
-  htsmsg_destroy(l);
-  return str;
+  return idnode_list_get_csv2(&ch->ch_services);
 }
 
 static int
 channel_class_services_set ( void *obj, const void *p )
 {
-  return channel_set_services_by_list(obj, (htsmsg_t*)p);
+  channel_t *ch = obj;
+  return idnode_list_set2(&ch->ch_id, &ch->ch_services,
+                          &service_class, (htsmsg_t *)p,
+                          service_mapper_create);
 }
 
 static htsmsg_t *
@@ -135,37 +116,30 @@ channel_class_services_enum ( void *obj )
 static const void *
 channel_class_tags_get ( void *obj )
 {
-  channel_tag_mapping_t *ctm;
   channel_t *ch = obj;
-  htsmsg_t *m = htsmsg_create_list();
-
-  /* Add all */
-  LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
-    htsmsg_add_str(m, NULL, idnode_uuid_as_str(&ctm->ctm_tag->ct_id));
-
-  return m;
+  return idnode_list_get2(&ch->ch_ctms);
 }
 
 static char *
 channel_class_tags_rend ( void *obj )
 {
-  char *str;
-  htsmsg_t   *l = htsmsg_create_list();
   channel_t *ch = obj;
-  channel_tag_mapping_t *ctm;
-
-  LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
-    htsmsg_add_str(l, NULL, ctm->ctm_tag->ct_name);
+  return idnode_list_get_csv2(&ch->ch_ctms);
+}
 
-  str = htsmsg_list_2_csv(l);
-  htsmsg_destroy(l);
-  return str;
+static int
+channel_class_tags_set_cb ( idnode_t *in1, idnode_t *in2, void *origin )
+{
+  return channel_tag_map((channel_tag_t *)in1, (channel_t *)in2, origin);
 }
 
 static int
 channel_class_tags_set ( void *obj, const void *p )
 {
-  return channel_set_tags_by_list(obj, (htsmsg_t*)p);
+  channel_t *ch = obj;
+  return idnode_list_set2(&ch->ch_id, &ch->ch_ctms,
+                          &channel_tag_class, (htsmsg_t *)p,
+                          channel_class_tags_set_cb);
 }
 
 static void
@@ -487,12 +461,12 @@ channel_access(channel_t *ch, access_t *a, int disabled)
 
   /* Channel tag check */
   if (a->aa_chtags) {
-    channel_tag_mapping_t *ctm;
+    idnode_list_mapping_t *ilm;
     htsmsg_field_t *f;
     HTSMSG_FOREACH(f, a->aa_chtags) {
-      LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
+      LIST_FOREACH(ilm, &ch->ch_ctms, ilm_in2_link) {
         if (!strcmp(htsmsg_field_get_str(f) ?: "",
-                    idnode_uuid_as_str(&ctm->ctm_tag->ct_id)))
+                    idnode_uuid_as_str(ilm->ilm_in1)))
           goto chtags_ok;
       }
     }
@@ -507,75 +481,15 @@ chtags_ok:
  * Property updating
  * *************************************************************************/
 
-int
-channel_set_services_by_list ( channel_t *ch, htsmsg_t *svcs )
-{
-  int save = 0;
-  const char *str;
-  service_t *svc;
-  htsmsg_field_t *f;
-  channel_service_mapping_t *csm;
-
-  /* Mark all for deletion */
-  LIST_FOREACH(csm, &ch->ch_services, csm_chn_link)
-    csm->csm_mark = 1;
-
-  /* Link */
-  HTSMSG_FOREACH(f, svcs) {
-    if ((str = htsmsg_field_get_str(f)))
-      if ((svc = service_find(str)))
-        save |= service_mapper_link(svc, ch, ch);
-  }
-
-  /* Remove */
-  save |= service_mapper_clean(NULL, ch, ch);
-
-  return save;
-}
-
-int
-channel_set_tags_by_list ( channel_t *ch, htsmsg_t *tags )
-{
-  int save = 0;
-  const char *uuid;
-  channel_tag_mapping_t *ctm, *n;
-  channel_tag_t *ct;
-  htsmsg_field_t *f;
-  
-  /* Mark for deletion */
-  LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
-    ctm->ctm_mark = 1;
-
-  /* Link */
-  HTSMSG_FOREACH(f, tags)
-    if ((uuid = htsmsg_field_get_str(f)) != NULL) {
-      if ((ct = channel_tag_find_by_uuid(uuid)))
-        save |= channel_tag_map(ch, ct);
-    }
-    
-  /* Remove */
-  for (ctm = LIST_FIRST(&ch->ch_ctms); ctm != NULL; ctm = n) {
-    n = LIST_NEXT(ctm, ctm_channel_link);
-    if (ctm->ctm_mark) {
-      LIST_REMOVE(ctm, ctm_channel_link);
-      LIST_REMOVE(ctm, ctm_tag_link);
-      free(ctm);
-      save = 1;
-    }
-  }
-
-  return save;
-}
-
 const char *
 channel_get_name ( channel_t *ch )
 {
   static const char *blank = CHANNEL_BLANK_NAME;
   const char *s;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
   if (ch->ch_name && *ch->ch_name) return ch->ch_name;
-  LIST_FOREACH(csm, &ch->ch_services, csm_chn_link)
-    if ((s = service_get_channel_name(csm->csm_svc)))
+  LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link)
+    if ((s = service_get_channel_name((service_t *)ilm->ilm_in1)))
       return s;
   return blank;
 }
@@ -597,15 +511,15 @@ int64_t
 channel_get_number ( channel_t *ch )
 {
   int64_t n = 0;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
   if (ch->ch_number) {
     n = ch->ch_number;
   } else {
-    LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) {
+    LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link) {
       if (ch->ch_bouquet &&
-          (n = bouquet_get_channel_number(ch->ch_bouquet, csm->csm_svc)))
+          (n = bouquet_get_channel_number(ch->ch_bouquet, (service_t *)ilm->ilm_in1)))
         break;
-      if ((n = service_get_channel_number(csm->csm_svc)))
+      if ((n = service_get_channel_number((service_t *)ilm->ilm_in1)))
         break;
     }
   }
@@ -642,7 +556,7 @@ const char *
 channel_get_icon ( channel_t *ch )
 {
   static char buf[512], buf2[512];
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
   const char *chicon = config_get_chicon_path(),
              *picon  = config_get_picon_path(),
              *icon   = ch->ch_icon,
@@ -718,9 +632,9 @@ channel_get_icon ( channel_t *ch )
 
     /* No user icon - try access from services */
     if (pick && picon) {
-      LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) {
+      LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link) {
         const char *icn;
-        if (!(icn = service_get_channel_icon(csm->csm_svc))) continue;
+        if (!(icn = service_get_channel_icon((service_t *)ilm->ilm_in1))) continue;
         if (strncmp(icn, "picon://", 8))
           continue;
         snprintf(buf2, sizeof(buf2), "%s/%s", picon, icn+8);
@@ -829,8 +743,7 @@ void
 channel_delete ( channel_t *ch, int delconf )
 {
   th_subscription_t *s;
-  channel_tag_mapping_t *ctm;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
 
   lock_assert(&global_lock);
 
@@ -838,8 +751,8 @@ channel_delete ( channel_t *ch, int delconf )
     tvhinfo("channel", "%s - deleting", channel_get_name(ch));
 
   /* Tags */
-  while((ctm = LIST_FIRST(&ch->ch_ctms)) != NULL)
-    channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_TAG);
+  while((ilm = LIST_FIRST(&ch->ch_ctms)) != NULL)
+    channel_tag_mapping_destroy(ilm, ch);
 
   /* DVR */
   autorec_destroy_by_channel(ch, delconf);
@@ -847,8 +760,8 @@ channel_delete ( channel_t *ch, int delconf )
   dvr_destroy_by_channel(ch, delconf);
 
   /* Services */
-  while((csm = LIST_FIRST(&ch->ch_services)) != NULL)
-    service_mapper_unlink(csm->csm_svc, ch, ch);
+  while((ilm = LIST_FIRST(&ch->ch_services)) != NULL)
+    idnode_list_unlink(ilm, ch);
 
   /* Subscriptions */
   while((s = LIST_FIRST(&ch->ch_subscriptions)) != NULL) {
@@ -934,44 +847,22 @@ channel_done ( void )
  *
  */
 int
-channel_tag_map(channel_t *ch, channel_tag_t *ct)
+channel_tag_map(channel_tag_t *ct, channel_t *ch, void *origin)
 {
-  channel_tag_mapping_t *ctm;
-
-  LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
-    if(ctm->ctm_tag == ct)
-      break;
-  if (!ctm)
-    LIST_FOREACH(ctm, &ct->ct_ctms, ctm_tag_link)
-      if(ctm->ctm_channel == ch)
-        break;
-
-  if (ctm) {
-    ctm->ctm_mark = 0;
-    return 0;
-  }
-
-  LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
-    assert(ctm->ctm_tag != ct);
-
-  LIST_FOREACH(ctm, &ct->ct_ctms, ctm_tag_link)
-    assert(ctm->ctm_channel != ch);
-
-  ctm = malloc(sizeof(channel_tag_mapping_t));
-
-  ctm->ctm_channel = ch;
-  LIST_INSERT_HEAD(&ch->ch_ctms, ctm, ctm_channel_link);
-
-  ctm->ctm_tag = ct;
-  LIST_INSERT_HEAD(&ct->ct_ctms, ctm, ctm_tag_link);
-
-  ctm->ctm_mark = 0;
-
-  if(ct->ct_enabled && !ct->ct_internal) {
-    htsp_tag_update(ct);
-    htsp_channel_update(ch);
+  idnode_list_mapping_t *ilm;
+
+  ilm = idnode_list_link(&ct->ct_id, &ct->ct_ctms,
+                         &ch->ch_id, &ch->ch_ctms,
+                         origin);
+  if (ilm) {
+    ilm->ilm_in2_save = 1; /* channel */
+    if(ct->ct_enabled && !ct->ct_internal) {
+      htsp_tag_update(ct);
+      htsp_channel_update(ch);
+    }
+    return 1;
   }
-  return 1;
+  return 0;
 }
 
 
@@ -979,19 +870,17 @@ channel_tag_map(channel_t *ch, channel_tag_t *ct)
  *
  */
 static void
-channel_tag_mapping_destroy(channel_tag_mapping_t *ctm, int flags)
+channel_tag_mapping_destroy(idnode_list_mapping_t *ilm, void *origin)
 {
-  channel_tag_t *ct = ctm->ctm_tag;
-  channel_t *ch = ctm->ctm_channel;
+  channel_tag_t *ct = (channel_tag_t *)ilm->ilm_in1;
+  channel_t *ch = (channel_t *)ilm->ilm_in2;
 
-  LIST_REMOVE(ctm, ctm_channel_link);
-  LIST_REMOVE(ctm, ctm_tag_link);
-  free(ctm);
+  idnode_list_unlink(ilm, origin);
 
   if(ct->ct_enabled && !ct->ct_internal) {
-    if(flags & CTM_DESTROY_UPDATE_TAG)
+    if(origin == ch)
       htsp_tag_update(ct);
-    if(flags & CTM_DESTROY_UPDATE_CHANNEL)
+    if(origin == ct)
       htsp_channel_update(ch);
   }
 }
@@ -1000,22 +889,14 @@ channel_tag_mapping_destroy(channel_tag_mapping_t *ctm, int flags)
  *
  */
 void
-channel_tag_unmap(channel_t *ch, channel_tag_t *ct)
+channel_tag_unmap(channel_t *ch, void *origin)
 {
-  channel_tag_mapping_t *ctm, *n;
-
-  for (ctm = LIST_FIRST(&ch->ch_ctms); ctm != NULL; ctm = n) {
-    n = LIST_NEXT(ctm, ctm_channel_link);
-    if (ctm->ctm_channel == ch) {
-      LIST_REMOVE(ctm, ctm_channel_link);
-      LIST_REMOVE(ctm, ctm_tag_link);
-      free(ctm);
-      channel_save(ch);
-      idnode_notify_changed(&ch->ch_id);
-      if (ct->ct_enabled && !ct->ct_internal) {
-        htsp_tag_update(ct);
-        htsp_channel_update(ch);
-      }
+  idnode_list_mapping_t *ilm, *n;
+
+  for (ilm = LIST_FIRST(&ch->ch_ctms); ilm != NULL; ilm = n) {
+    n = LIST_NEXT(ilm, ilm_in2_link);
+    if ((channel_t *)ilm->ilm_in2 == ch) {
+      channel_tag_mapping_destroy(ilm, origin);
       return;
     }
   }
@@ -1061,15 +942,11 @@ channel_tag_create(const char *uuid, htsmsg_t *conf)
 static void
 channel_tag_destroy(channel_tag_t *ct, int delconf)
 {
-  channel_tag_mapping_t *ctm;
-  channel_t *ch;
+  idnode_list_mapping_t *ilm;
 
   if (delconf) {
-    while((ctm = LIST_FIRST(&ct->ct_ctms)) != NULL) {
-      ch = ctm->ctm_channel;
-      channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_CHANNEL);
-      channel_save(ch);
-    }
+    while((ilm = LIST_FIRST(&ct->ct_ctms)) != NULL)
+      channel_tag_mapping_destroy(ilm, ilm->ilm_in1);
     hts_settings_remove("channel/tag/%s", idnode_uuid_as_str(&ct->ct_id));
   }
 
index 92f51eab404151145a86484183a9d350d8eefe87..2ebc5e00978ede9be353174ec9e779aceee47648 100644 (file)
@@ -27,7 +27,6 @@ struct bouquet;
 
 RB_HEAD(channel_tree, channel);
 
-LIST_HEAD(channel_tag_mapping_list, channel_tag_mapping);
 TAILQ_HEAD(channel_tag_queue, channel_tag);
 
 extern struct channel_tag_queue channel_tags;
@@ -53,12 +52,12 @@ typedef struct channel
   char   *ch_name; // Note: do not access directly!
   int64_t ch_number;
   char   *ch_icon;
-  struct  channel_tag_mapping_list ch_ctms;
+  idnode_list_head_t ch_ctms;
   struct bouquet *ch_bouquet;
 
   /* Service/subscriptions */
-  LIST_HEAD(, channel_service_mapping) ch_services;
-  LIST_HEAD(, th_subscription)         ch_subscriptions;
+  idnode_list_head_t           ch_services;
+  LIST_HEAD(, th_subscription) ch_subscriptions;
 
   /* EPG fields */
   epg_broadcast_tree_t  ch_epg_schedule;
@@ -99,7 +98,7 @@ typedef struct channel_tag {
   char *ct_comment;
   char *ct_icon;
 
-  struct channel_tag_mapping_list ct_ctms;
+  idnode_list_head_t ct_ctms;
 
   struct dvr_autorec_entry_list ct_autorecs;
 
@@ -109,33 +108,6 @@ typedef struct channel_tag {
 
 } channel_tag_t;
 
-/**
- * Channel tag mapping
- */
-typedef struct channel_tag_mapping {
-  LIST_ENTRY(channel_tag_mapping) ctm_channel_link;
-  channel_t *ctm_channel;
-  
-  LIST_ENTRY(channel_tag_mapping) ctm_tag_link;
-  channel_tag_t *ctm_tag;
-
-  int ctm_mark;
-
-} channel_tag_mapping_t;
-
-/*
- * Service mappings
- */
-typedef struct channel_service_mapping {
-  LIST_ENTRY(channel_service_mapping) csm_chn_link;
-  LIST_ENTRY(channel_service_mapping) csm_svc_link;
-  
-  struct channel *csm_chn;
-  struct service *csm_svc;
-
-  int csm_mark;
-} channel_service_mapping_t;
-
 extern const idclass_t channel_class;
 extern const idclass_t channel_tag_class;
 
@@ -163,7 +135,6 @@ channel_t *channel_find_by_number(const char *no);
 htsmsg_t * channel_class_get_list(void *o);
 
 int channel_set_tags_by_list ( channel_t *ch, htsmsg_t *tags );
-int channel_set_services_by_list ( channel_t *ch, htsmsg_t *svcs );
 
 channel_tag_t *channel_tag_create(const char *uuid, htsmsg_t *conf);
 
@@ -182,8 +153,8 @@ const char * channel_tag_get_icon(channel_tag_t *ct);
 
 int channel_access(channel_t *ch, struct access *a, int disabled);
 
-int channel_tag_map(channel_t *ch, channel_tag_t *ct);
-void channel_tag_unmap(channel_t *ch, channel_tag_t *ct);
+int channel_tag_map(channel_tag_t *ct, channel_t *ch, void *origin);
+void channel_tag_unmap(channel_t *ch, void *origin);
 
 int channel_tag_access(channel_tag_t *ct, struct access *a, int disabled);
 
@@ -203,8 +174,8 @@ int channel_set_number ( channel_t *ch, uint32_t major, uint32_t minor );
 const char *channel_get_icon ( channel_t *ch );
 int channel_set_icon ( channel_t *ch, const char *icon );
 
-#define channel_get_uuid(ch) idnode_uuid_as_str(&ch->ch_id)
+#define channel_get_uuid(ch) idnode_uuid_as_str(&(ch)->ch_id)
 
-#define channel_get_id(ch)   idnode_get_short_uuid((&ch->ch_id))
+#define channel_get_id(ch)   idnode_get_short_uuid((&(ch)->ch_id))
 
 #endif /* CHANNELS_H */
index 07efd5834104bc2c35fe048987877dfcce616549..7112da68f19a9fa693aaa5c1be900d318ab499cc 100644 (file)
@@ -63,7 +63,7 @@ dvr_autorec_purge_spawns(dvr_autorec_entry_t *dae, int del)
 static int
 autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
 {
-  channel_tag_mapping_t *ctm;
+  idnode_list_mapping_t *ilm;
   dvr_config_t *cfg;
   double duration;
 
@@ -130,10 +130,10 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
   }
 
   if(dae->dae_channel_tag != NULL) {
-    LIST_FOREACH(ctm, &dae->dae_channel_tag->ct_ctms, ctm_tag_link)
-      if(ctm->ctm_channel == e->channel)
+    LIST_FOREACH(ilm, &dae->dae_channel_tag->ct_ctms, ilm_in1_link)
+      if((channel_t *)ilm->ilm_in2 == e->channel)
        break;
-    if(ctm == NULL)
+    if(ilm == NULL)
       return 0;
   }
 
index 0889880c2e8a779e7e3f88b1a90c8439fb4b303f..f0ba80683242d47702c426007a62538637bb2597 100644 (file)
--- a/src/epg.c
+++ b/src/epg.c
@@ -2581,10 +2581,10 @@ epg_query ( epg_query_t *eq, access_t *perm )
   
   /* Tag based */
   } else if (tag) {
-    channel_tag_mapping_t *ctm;
+    idnode_list_mapping_t *ilm;
     channel_t *ch2;
-    LIST_FOREACH(ctm, &tag->ct_ctms, ctm_tag_link) {
-      ch2 = ctm->ctm_channel;
+    LIST_FOREACH(ilm, &tag->ct_ctms, ilm_in1_link) {
+      ch2 = (channel_t *)ilm->ilm_in2;
       if(ch2 == channel || channel == NULL)
         if (channel_access(ch2, perm, 0))
           _eq_add_channel(eq, ch2);
index c1dc40b735794f028dbbb2940c03ec360c03984f..1079b956801d8eb5222d842c15a6fa19e96a22c6 100644 (file)
@@ -557,13 +557,14 @@ static int _eit_process_event
     mpegts_service_t *svc, const uint8_t *ptr, int len,
     int local, int *resched, int *save )
 {
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
   int ret = 0;
 
   if ( len < 12 ) return -1;
 
-  LIST_FOREACH(csm, &svc->s_channels, csm_svc_link)
-    ret = _eit_process_event_one(mod, tableid, svc, csm->csm_chn,
+  LIST_FOREACH(ilm, &svc->s_channels, ilm_in1_link)
+    ret = _eit_process_event_one(mod, tableid, svc,
+                                 (channel_t *)ilm->ilm_in2,
                                  ptr, len, local, resched, save);
   return ret;
 }
index c104c738daa31766c5bc7f747d27e51d8207c85a..9ff7d1bc1ebf7e5de4effef16455de7268d3dfea 100644 (file)
@@ -516,7 +516,7 @@ skip_chnum:
     if (svc && LIST_FIRST(&svc->s_channels)) {
       ec  =_opentv_find_epggrab_channel(mod, cid, 1, &save);
       ecl = LIST_FIRST(&ec->channels);
-      ch  = LIST_FIRST(&svc->s_channels)->csm_chn;
+      ch  = (channel_t *)LIST_FIRST(&svc->s_channels)->ilm_in2;
       tvhtrace(mt->mt_name, "       ec = %p, ecl = %p", ec, ecl);
 
       if (ecl && ecl->ecl_channel != ch) {
index 37cdfd17d81bf9c37140d7a7c93f30ed71ae315c..fef799aa39f9599a55c35a0ac1fcb97f32feb291 100644 (file)
@@ -592,8 +592,7 @@ htsp_file_destroy(htsp_file_t *hf)
 static htsmsg_t *
 htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp)
 {
-  channel_tag_mapping_t *ctm;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
   channel_tag_t *ct;
   service_t *t;
   epg_broadcast_t *now, *next = NULL;
@@ -647,14 +646,14 @@ htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp)
   htsmsg_add_u32(out, "eventId", now ? now->id : 0);
   htsmsg_add_u32(out, "nextEventId", next ? next->id : 0);
 
-  LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
-    ct = ctm->ctm_tag;
+  LIST_FOREACH(ilm, &ch->ch_ctms, ilm_in2_link) {
+    ct = (channel_tag_t *)ilm->ilm_in1;
     if(channel_tag_access(ct, htsp->htsp_granted_access, 0))
       htsmsg_add_u32(tags, NULL, htsp_channel_tag_get_identifier(ct));
   }
 
-  LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) {
-    t = csm->csm_svc;
+  LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link) {
+    t = (service_t *)ilm->ilm_in1;
     htsmsg_t *svcmsg = htsmsg_create_map();
     uint16_t caid;
     htsmsg_add_str(svcmsg, "name", service_nicename(t));
@@ -679,7 +678,7 @@ htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp)
 static htsmsg_t *
 htsp_build_tag(channel_tag_t *ct, const char *method, int include_channels)
 {
-  channel_tag_mapping_t *ctm;
+  idnode_list_mapping_t *ilm;
   htsmsg_t *out = htsmsg_create_map();
   htsmsg_t *members = include_channels ? htsmsg_create_list() : NULL;
  
@@ -691,8 +690,8 @@ htsp_build_tag(channel_tag_t *ct, const char *method, int include_channels)
   htsmsg_add_u32(out, "tagTitledIcon", ct->ct_titled_icon);
 
   if(members != NULL) {
-    LIST_FOREACH(ctm, &ct->ct_ctms, ctm_tag_link)
-      htsmsg_add_u32(members, NULL, channel_get_id(ctm->ctm_channel));
+    LIST_FOREACH(ilm, &ct->ct_ctms, ilm_in1_link)
+      htsmsg_add_u32(members, NULL, channel_get_id((channel_t *)ilm->ilm_in2));
     htsmsg_add_msg(out, "members", members);
   }
 
index d6011da24d49828b938f8bad9042947d7d536252..18ef88d2d4155e92ac61cefb9b32995072c482d3 100644 (file)
@@ -1328,6 +1328,222 @@ idnode_serialize0(idnode_t *self, htsmsg_t *list, int optmask)
   return m;
 }
 
+/* **************************************************************************
+ * List helpers
+ * *************************************************************************/
+
+static void
+idnode_list_notify ( idnode_list_mapping_t *ilm, void *origin )
+{
+  if (origin == NULL)
+    return;
+  if (origin == ilm->ilm_in1) {
+    idnode_notify_changed(ilm->ilm_in2);
+    if (ilm->ilm_in2_save)
+      idnode_savefn(ilm->ilm_in2);
+  }
+  if (origin == ilm->ilm_in2) {
+    idnode_notify_changed(ilm->ilm_in1);
+    if (ilm->ilm_in1_save)
+      idnode_savefn(ilm->ilm_in1);
+  }
+}
+
+/*
+ * Link class1 and class2
+ */
+idnode_list_mapping_t *
+idnode_list_link ( idnode_t *in1, idnode_list_head_t *in1_list,
+                   idnode_t *in2, idnode_list_head_t *in2_list,
+                   void *origin )
+{
+  idnode_list_mapping_t *ilm;
+
+  /* Already linked */
+  LIST_FOREACH(ilm, in1_list, ilm_in1_link)
+    if (ilm->ilm_in2 == in2) {
+      ilm->ilm_mark = 0;
+      return NULL;
+    }
+  LIST_FOREACH(ilm, in2_list, ilm_in2_link)
+    if (ilm->ilm_in1 == in1) {
+      ilm->ilm_mark = 0;
+      return NULL;
+    }
+
+  /* Link */
+  ilm = calloc(1, sizeof(idnode_list_mapping_t));
+  ilm->ilm_in1 = in1;
+  ilm->ilm_in2 = in2;
+  LIST_INSERT_HEAD(in1_list, ilm, ilm_in1_link);
+  LIST_INSERT_HEAD(in2_list, ilm, ilm_in2_link);
+  idnode_list_notify(ilm, origin);
+  return ilm;
+}
+
+void
+idnode_list_unlink ( idnode_list_mapping_t *ilm, void *origin )
+{
+  LIST_REMOVE(ilm, ilm_in1_link);
+  LIST_REMOVE(ilm, ilm_in2_link);
+  idnode_list_notify(ilm, origin);
+  free(ilm);
+}
+
+static int
+idnode_list_clean
+  ( idnode_t *in1, idnode_list_head_t *in1_list,
+    idnode_t *in2, idnode_list_head_t *in2_list,
+    void *origin )
+{
+  int save = 0;
+  idnode_list_mapping_t *ilm, *n;
+
+  for (ilm = LIST_FIRST(in1 ? in1_list : in2_list); ilm != NULL; ilm = n) {
+    n = in1 ? LIST_NEXT(ilm, ilm_in1_link) : LIST_NEXT(ilm, ilm_in2_link);
+    if (ilm->ilm_mark) {
+      idnode_list_unlink(ilm, origin);
+      save = 1;
+    }
+  }
+  return save;
+}
+
+htsmsg_t *
+idnode_list_get1
+  ( idnode_list_head_t *in1_list )
+{
+  idnode_list_mapping_t *ilm;
+  htsmsg_t *l = htsmsg_create_list();
+
+  LIST_FOREACH(ilm, in1_list, ilm_in1_link)
+    htsmsg_add_str(l, NULL, idnode_uuid_as_str(ilm->ilm_in2));
+  return l;
+}
+
+htsmsg_t *
+idnode_list_get2
+  ( idnode_list_head_t *in2_list )
+{
+  idnode_list_mapping_t *ilm;
+  htsmsg_t *l = htsmsg_create_list();
+
+  LIST_FOREACH(ilm, in2_list, ilm_in2_link)
+    htsmsg_add_str(l, NULL, idnode_uuid_as_str(ilm->ilm_in1));
+  return l;
+}
+
+char *
+idnode_list_get_csv1
+  ( idnode_list_head_t *in1_list )
+{
+  char *str;
+  idnode_list_mapping_t *ilm;
+  htsmsg_t *l = htsmsg_create_list();
+
+  LIST_FOREACH(ilm, in1_list, ilm_in1_link)
+    htsmsg_add_str(l, NULL, idnode_get_title(ilm->ilm_in2));
+
+  str = htsmsg_list_2_csv(l);
+  htsmsg_destroy(l);
+  return str;
+}
+
+char *
+idnode_list_get_csv2
+  ( idnode_list_head_t *in2_list )
+{
+  char *str;
+  idnode_list_mapping_t *ilm;
+  htsmsg_t *l = htsmsg_create_list();
+
+  LIST_FOREACH(ilm, in2_list, ilm_in2_link)
+    htsmsg_add_str(l, NULL, idnode_get_title(ilm->ilm_in1));
+
+  str = htsmsg_list_2_csv(l);
+  htsmsg_destroy(l);
+  return str;
+}
+
+int
+idnode_list_set1
+  ( idnode_t *in1, idnode_list_head_t *in1_list,
+    const idclass_t *in2_class, htsmsg_t *in2_list,
+    int (*in2_create)(idnode_t *in1, idnode_t *in2, void *origin) )
+{
+  const char *str;
+  htsmsg_field_t *f;
+  idnode_t *in2;
+  idnode_list_mapping_t *ilm;
+  int save = 0;
+
+  /* Mark all for deletion */
+  LIST_FOREACH(ilm, in1_list, ilm_in1_link)
+    ilm->ilm_mark = 1;
+
+  /* Make new links */
+  HTSMSG_FOREACH(f, in2_list)
+    if ((str = htsmsg_field_get_str(f)))
+      if ((in2 = idnode_find(str, in2_class, NULL)) != NULL)
+        if (in2_create(in1, in2, in1))
+          save = 1;
+
+  /* Delete unlinked */
+  if (idnode_list_clean(in1, in1_list, NULL, NULL, in1))
+    save = 1;
+
+  /* Change notification */
+  if (save)
+    idnode_notify_changed(in1);
+
+  /* Save only on demand */
+  ilm = LIST_FIRST(in1_list);
+  if (ilm && !ilm->ilm_in1_save)
+    save = 0;
+
+  return save;
+}
+
+int
+idnode_list_set2
+  ( idnode_t *in2, idnode_list_head_t *in2_list,
+    const idclass_t *in1_class, htsmsg_t *in1_list,
+    int (*in1_create)(idnode_t *in1, idnode_t *in2, void *origin) )
+{
+  const char *str;
+  htsmsg_field_t *f;
+  idnode_t *in1;
+  idnode_list_mapping_t *ilm;
+  int save = 0;
+
+  /* Mark all for deletion */
+  LIST_FOREACH(ilm, in2_list, ilm_in2_link)
+    ilm->ilm_mark = 1;
+
+  /* Make new links */
+  HTSMSG_FOREACH(f, in1_list)
+    if ((str = htsmsg_field_get_str(f)))
+      if ((in1 = idnode_find(str, in1_class, NULL)) != NULL)
+        if (in1_create(in1, in2, in2))
+          save = 1;
+
+  /* Delete unlinked */
+  if (idnode_list_clean(in2, in2_list, NULL, NULL, in2))
+    save = 1;
+
+  /* Change notification */
+  if (save)
+    idnode_notify_changed(in2);
+
+  /* Save only on demand */
+  ilm = LIST_FIRST(in2_list);
+  if (ilm && !ilm->ilm_in2_save)
+    save = 0;
+
+  return save;
+}
+
+
 /* **************************************************************************
  * Notification
  * *************************************************************************/
index fcd6b6117931d83468c4365a3640c91cf2396a94..fb335b442a92a84937e71b0ea26b2d977aa44c87 100644 (file)
@@ -91,6 +91,27 @@ struct idnode {
 
 };
 
+/*
+ * Node list mapping definition
+ */
+struct idnode_list_mapping;
+
+typedef struct idnode_list_head {
+  struct idnode_list_mapping *lh_first;
+} idnode_list_head_t;
+
+typedef struct idnode_list_mapping {
+  LIST_ENTRY(idnode_list_mapping) ilm_in1_link;
+  LIST_ENTRY(idnode_list_mapping) ilm_in2_link;
+
+  idnode_t *ilm_in1;
+  idnode_t *ilm_in2;
+
+  uint8_t ilm_in1_save;
+  uint8_t ilm_in2_save;
+  uint8_t ilm_mark;
+} idnode_list_mapping_t;
+
 /*
  * Sorting definition
  */
@@ -183,6 +204,22 @@ int idnode_perm(idnode_t *self, struct access *a, htsmsg_t *msg_to_write);
 static inline void idnode_perm_set(idnode_t *self, struct access *a) { self->in_access = a; }
 static inline void idnode_perm_unset(idnode_t *self) { self->in_access = NULL; }
 
+idnode_list_mapping_t * idnode_list_link
+                       ( idnode_t *in1, idnode_list_head_t *in1_list,
+                         idnode_t *in2, idnode_list_head_t *in2_list,
+                         void *origin );
+void idnode_list_unlink ( idnode_list_mapping_t *ilm, void *origin );
+htsmsg_t * idnode_list_get1 ( idnode_list_head_t *in1_list );
+htsmsg_t * idnode_list_get2 ( idnode_list_head_t *in2_list );
+char * idnode_list_get_csv1 ( idnode_list_head_t *in1_list );
+char * idnode_list_get_csv2 ( idnode_list_head_t *in2_list );
+int idnode_list_set1 ( idnode_t *in1, idnode_list_head_t *in1_list,
+                       const idclass_t *in2_class, htsmsg_t *in2_list,
+                       int (*in2_create)(idnode_t *in1, idnode_t *in2, void *origin) );
+int idnode_list_set2 ( idnode_t *in2, idnode_list_head_t *in2_list,
+                       const idclass_t *in1_class, htsmsg_t *in1_list,
+                       int (*in2_create)(idnode_t *in1, idnode_t *in2, void *origin) );
+
 const char *idnode_get_str (idnode_t *self, const char *key );
 int         idnode_get_u32 (idnode_t *self, const char *key, uint32_t *u32);
 int         idnode_get_s64 (idnode_t *self, const char *key,  int64_t *s64);
index 20fc493b8d8efd71f8278bc5089406fdb2580ccf..4f68a5db7e9fa230caa94fe53d44b1dc74dddc62 100644 (file)
@@ -331,11 +331,11 @@ mpegts_mux_class_get_num_chn ( void *ptr )
   static int n;
   mpegts_mux_t *mm = ptr;
   mpegts_service_t *s;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
 
   n = 0;
   LIST_FOREACH(s, &mm->mm_services, s_dvb_mux_link)
-    LIST_FOREACH(csm, &s->s_channels, csm_svc_link)
+    LIST_FOREACH(ilm, &s->s_channels, ilm_in1_link)
       n++;
 
   return &n;
index 9311ffc8d900f95235b3af7620247d4910e74b09..c81a0a58b518704797a5a9d218bb8445042282a8 100644 (file)
@@ -85,12 +85,12 @@ mpegts_network_class_get_num_chn ( void *ptr )
   mpegts_mux_t *mm;
   mpegts_service_t *s;
   mpegts_network_t *mn = ptr;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
 
   n = 0;
   LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link)
     LIST_FOREACH(s, &mm->mm_services, s_dvb_mux_link)
-      LIST_FOREACH(csm, &s->s_channels, csm_svc_link)
+      LIST_FOREACH(ilm, &s->s_channels, ilm_in1_link)
         n++;
 
   return &n;
index a66a3e743451c7be6a984f5e2b2334e98790e639..373c724d6c79477d25da2b80126dab9641b70fde 100644 (file)
@@ -69,29 +69,14 @@ static const void *
 service_class_channel_get ( void *obj )
 {
   service_t *svc = obj;
-  channel_service_mapping_t *csm;
-
-  htsmsg_t *l = htsmsg_create_list();
-  LIST_FOREACH(csm, &svc->s_channels, csm_svc_link)
-    htsmsg_add_str(l, NULL, idnode_uuid_as_str(&csm->csm_chn->ch_id));
-  
-  return l;
+  return idnode_list_get1(&svc->s_channels);
 }
 
 static char *
 service_class_channel_rend ( void *obj )
 {
-  char *str;
   service_t *svc = obj;
-  channel_service_mapping_t *csm;
-
-  htsmsg_t *l = htsmsg_create_list();
-  LIST_FOREACH(csm, &svc->s_channels, csm_svc_link)
-    htsmsg_add_str(l, NULL, idnode_get_title(&csm->csm_chn->ch_id));
-
-  str = htsmsg_list_2_csv(l);
-  htsmsg_destroy(l);
-  return str;
+  return idnode_list_get_csv1(&svc->s_channels);
 }
 
 static int
@@ -99,30 +84,9 @@ service_class_channel_set
   ( void *obj, const void *p )
 {
   service_t *svc = obj;
-  htsmsg_t  *chns = (htsmsg_t*)p;
-  const char *str;
-  htsmsg_field_t *f;
-  channel_t *ch;
-  channel_service_mapping_t *csm;
-
-  /* Mark all for deletion */
-  LIST_FOREACH(csm, &svc->s_channels, csm_svc_link)
-    csm->csm_mark = 1;
-
-  /* Make new links */
-  HTSMSG_FOREACH(f, chns) {
-    if ((str = htsmsg_field_get_str(f)))
-      if ((ch = channel_find(str)))
-        service_mapper_link(svc, ch, svc);
-  }
-
-  /* Delete unlinked */
-  service_mapper_clean(svc, NULL, svc);
-
-  /* no save - the link information is in the saved channel record */
-  /* only send a notify about the change to other clients */
-  idnode_notify_changed(&svc->s_id);
-  return 0;
+  return idnode_list_set1(&svc->s_id, &svc->s_channels,
+                          &channel_class, (htsmsg_t *)p,
+                          service_mapper_create);
 }
 
 static htsmsg_t *
@@ -699,7 +663,7 @@ service_find_instance
    profile_chain_t *prch, service_instance_list_t *sil,
    int *error, int weight, int flags, int timeout, int postpone)
 {
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
   service_instance_t *si, *next;
   profile_t *pro = prch ? prch->prch_pro : NULL;
   int enlisted, weight2;
@@ -716,8 +680,8 @@ service_find_instance
       return NULL;
     }
     enlisted = 0;
-    LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) {
-      s = csm->csm_svc;
+    LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link) {
+      s = (service_t *)ilm->ilm_in1;
       if (s->s_is_enabled(s, flags)) {
         if (pro == NULL ||
             pro->pro_svfilter == PROFILE_SVF_NONE ||
@@ -729,8 +693,8 @@ service_find_instance
       }
     }
     if (enlisted == 0) {
-      LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) {
-        s = csm->csm_svc;
+      LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link) {
+        s = (service_t *)ilm->ilm_in1;
         if (s->s_is_enabled(s, flags))
           s->s_enlist(s, ti, sil, flags);
       }
@@ -838,7 +802,7 @@ service_destroy(service_t *t, int delconf)
 {
   elementary_stream_t *st;
   th_subscription_t *s;
-  channel_service_mapping_t *csm;
+  idnode_list_mapping_t *ilm;
 
   if(t->s_delete != NULL)
     t->s_delete(t, delconf);
@@ -851,11 +815,8 @@ service_destroy(service_t *t, int delconf)
     subscription_unlink_service(s, SM_CODE_SOURCE_DELETED);
   }
 
-  while ((csm = LIST_FIRST(&t->s_channels))) {
-    LIST_REMOVE(csm, csm_svc_link);
-    LIST_REMOVE(csm, csm_chn_link);
-    free(csm);
-  }
+  while ((ilm = LIST_FIRST(&t->s_channels)))
+    idnode_list_unlink(ilm, t);
 
   idnode_unlink(&t->s_id);
 
index 3307babb07e9f47dd32038a2c4c99cbd0bdc72b6..1c1187e3b5be49c4b53d6272bc38baa0d2704ef0 100644 (file)
@@ -336,7 +336,7 @@ typedef struct service {
   /**
    * Channel mapping
    */
-  LIST_HEAD(,channel_service_mapping) s_channels;
+  idnode_list_head_t s_channels;
 
   /**
    * Service mapping, see service_mapper.c form details
index cf5414b357142d509cba747a30b456fd2ae3c827..37cb8eb88a435bd356fd279ce7d87c76e8116622 100644 (file)
@@ -178,88 +178,29 @@ service_mapper_remove ( service_t *s )
   api_service_mapper_notify();
 }
 
-static void
-service_mapper_notify ( channel_service_mapping_t *csm, void *origin )
-{
-  if (origin == NULL)
-    return;
-  if (origin == csm->csm_svc) {
-    idnode_notify_changed(&csm->csm_chn->ch_id);
-    channel_save(csm->csm_chn);
-  }
-  if (origin == csm->csm_chn)
-    idnode_notify_changed(&csm->csm_svc->s_id);
-}
-
 /*
  * Link service and channel
  */
 int
 service_mapper_link ( service_t *s, channel_t *c, void *origin )
 {
-  channel_service_mapping_t *csm;
-
-  /* Already linked */
-  LIST_FOREACH(csm, &s->s_channels, csm_svc_link)
-    if (csm->csm_chn == c) {
-      csm->csm_mark = 0;
-      return 0;
-    }
-  LIST_FOREACH(csm, &c->ch_services, csm_chn_link)
-    if (csm->csm_svc == s) {
-      csm->csm_mark = 0;
-      return 0;
-    }
-
-  /* Link */
-  csm = calloc(1, sizeof(channel_service_mapping_t));
-  csm->csm_chn = c;
-  csm->csm_svc = s;
-  LIST_INSERT_HEAD(&s->s_channels,  csm, csm_svc_link);
-  LIST_INSERT_HEAD(&c->ch_services, csm, csm_chn_link);
-  service_mapped( s );
-  service_mapper_notify( csm, origin );
-  return 1;
-}
-
-static void
-service_mapper_unlink0 ( channel_service_mapping_t *csm, void *origin )
-{
-  LIST_REMOVE(csm, csm_chn_link);
-  LIST_REMOVE(csm, csm_svc_link);
-  service_mapper_notify( csm, origin );
-  free(csm);
-}
-
-void
-service_mapper_unlink ( service_t *s, channel_t *c, void *origin )
-{
-  channel_service_mapping_t *csm;
-
-  /* Unlink */
-  LIST_FOREACH(csm, &s->s_channels, csm_svc_link) {
-    if (csm->csm_chn == c) {
-      service_mapper_unlink0(csm, origin);
-      break;
-    }
+  idnode_list_mapping_t *ilm;
+
+  ilm = idnode_list_link(&s->s_id, &s->s_channels,
+                         &c->ch_id, &c->ch_services,
+                         origin);
+  if (ilm) {
+    service_mapped(s);
+    ilm->ilm_in2_save = 1; /* channel */
+    return 1;
   }
+  return 0;
 }
 
 int
-service_mapper_clean ( service_t *s, channel_t *c, void *origin )
+service_mapper_create ( idnode_t *s, idnode_t *c, void *origin )
 {
-  int save = 0;
-  channel_service_mapping_t *csm, *n;
-
-  csm = s ? LIST_FIRST(&s->s_channels) : LIST_FIRST(&c->ch_services);
-  for (; csm != NULL; csm = n ) {
-    n = s ? LIST_NEXT(csm, csm_svc_link) : LIST_NEXT(csm, csm_chn_link);
-    if (csm->csm_mark) {
-      service_mapper_unlink0(csm, origin);
-      save = 1;
-    }
-  }
-  return save;
+  return service_mapper_link((service_t *)s, (channel_t *)c, origin);
 }
 
 /*
@@ -300,19 +241,19 @@ service_mapper_process ( service_t *s, bouquet_t *bq )
 
     /* Type tags */
     if (service_is_hdtv(s)) {
-      channel_tag_map(chn, channel_tag_find_by_name("TV channels", 1));
-      channel_tag_map(chn, channel_tag_find_by_name("HDTV", 1));
+      channel_tag_map(channel_tag_find_by_name("TV channels", 1), chn, chn);
+      channel_tag_map(channel_tag_find_by_name("HDTV", 1), chn, chn);
     } else if (service_is_sdtv(s)) {
-      channel_tag_map(chn, channel_tag_find_by_name("TV channels", 1));
-      channel_tag_map(chn, channel_tag_find_by_name("SDTV", 1));
+      channel_tag_map(channel_tag_find_by_name("TV channels", 1), chn, chn);
+      channel_tag_map(channel_tag_find_by_name("SDTV", 1), chn, chn);
     } else if (service_is_radio(s)) {
-      channel_tag_map(chn, channel_tag_find_by_name("Radio", 1));
+      channel_tag_map(channel_tag_find_by_name("Radio", 1), chn, chn);
     }
 
     /* Provider */
     if (service_mapper_conf.provider_tags)
       if ((prov = s->s_provider_name(s)))
-        channel_tag_map(chn, channel_tag_find_by_name(prov, 1));
+        channel_tag_map(channel_tag_find_by_name(prov, 1), chn, chn);
 
     /* save */
     idnode_notify_changed(&chn->ch_id);
index 6651d66f8854370cdae5713d13dd6fb1a6559e9b..b8dfaf3863db9311a1d1d547f00579239f322693 100644 (file)
@@ -57,22 +57,8 @@ service_mapper_status_t service_mapper_status ( void );
 // Link service to channel
 int  service_mapper_link   ( struct service *s, struct channel *c, void *origin );
 
-// Unlink service from channel
-void service_mapper_unlink ( struct service *s, struct channel *c, void *origin );
-
-/**
- * Clean linkages that are marked for deletion
- *
- * Note: only ever pass one of s and c
- *
- * @param s       The service to clean linkages for
- * @param c       The channel to clean linkages for
- * @parma origin  Origin of the change (should be a service or a channel ptr).
- *                NULL = no save and notifications.
- *
- * @return 1 if changes were made, else 0
- */
-int service_mapper_clean ( struct service *s, struct channel *ch, void *origin );
+// Create new link
+int service_mapper_create ( idnode_t *s, idnode_t *c, void *origin );
 
 // Process one service
 struct channel *service_mapper_process ( struct service *s, struct bouquet *bq );
index 4a7578bd7f0bf8f0e0a36746c8aa23ec3377ecf3..76b31e80a43b0171423b46a0f5e3477a3b7e47a0 100644 (file)
@@ -442,8 +442,9 @@ http_tag_playlist(http_connection_t *hc, channel_tag_t *tag)
 {
   htsbuf_queue_t *hq;
   char buf[255];
-  channel_tag_mapping_t *ctm;
+  idnode_list_mapping_t *ilm;
   char *profile, *hostpath;
+  channel_t *ch;
 
   if(hc->hc_access == NULL ||
      access_verify2(hc->hc_access, ACCESS_STREAMING))
@@ -455,11 +456,12 @@ http_tag_playlist(http_connection_t *hc, channel_tag_t *tag)
   hostpath = http_get_hostpath(hc);
 
   htsbuf_qprintf(hq, "#EXTM3U\n");
-  LIST_FOREACH(ctm, &tag->ct_ctms, ctm_tag_link) {
-    if (http_access_verify_channel(hc, ACCESS_STREAMING, ctm->ctm_channel, 0))
+  LIST_FOREACH(ilm, &tag->ct_ctms, ilm_in1_link) {
+    ch = (channel_t *)ilm->ilm_in2;
+    if (http_access_verify_channel(hc, ACCESS_STREAMING, ch, 0))
       continue;
-    snprintf(buf, sizeof(buf), "/stream/channelid/%d", channel_get_id(ctm->ctm_channel));
-    htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", channel_get_name(ctm->ctm_channel));
+    snprintf(buf, sizeof(buf), "/stream/channelid/%d", channel_get_id(ch));
+    htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", channel_get_name(ch));
     htsbuf_qprintf(hq, "%s%s?ticket=%s", hostpath, buf,
        access_ticket_create(buf, hc->hc_access));
     htsbuf_qprintf(hq, "&profile=%s\n", profile);