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;
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);
+ }
}
/*
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);
}
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;
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;
}
}
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);
}
}
{
bouquet_t *bq = obj;
service_t *t;
- channel_service_mapping_t *csm;
+ idnode_list_mapping_t *ilm;
channel_tag_t *ct;
size_t z;
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);
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 )
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 *
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
/* 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;
}
}
* 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;
}
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;
}
}
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,
/* 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);
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);
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);
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) {
*
*/
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;
}
*
*/
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);
}
}
*
*/
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;
}
}
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));
}
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;
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;
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;
} 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;
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);
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);
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 */
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;
}
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;
}
/* 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);
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;
}
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) {
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;
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));
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;
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);
}
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
* *************************************************************************/
};
+/*
+ * 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
*/
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);
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;
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;
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
( 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 *
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;
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 ||
}
}
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);
}
{
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);
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);
/**
* Channel mapping
*/
- LIST_HEAD(,channel_service_mapping) s_channels;
+ idnode_list_head_t s_channels;
/**
* Service mapping, see service_mapper.c form details
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);
}
/*
/* 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);
// 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 );
{
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))
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);