Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
channel enhancements (enabled), fixed min/max chnum handling (access)
  • Loading branch information
perexg committed Nov 21, 2014
1 parent 00f3cc0 commit da3d9ec
Show file tree
Hide file tree
Showing 14 changed files with 87 additions and 45 deletions.
10 changes: 6 additions & 4 deletions src/access.c
Expand Up @@ -348,7 +348,7 @@ access_dump_a(access_t *a)
int first;

snprintf(buf, sizeof(buf),
"%s:%s [%s%s%s%s%s], conn=%u, chmin=%u, chmax=%u%s",
"%s:%s [%s%s%s%s%s], conn=%u, chmin=%llu, chmax=%llu%s",
a->aa_representative ?: "<no-id>",
a->aa_username ?: "<no-user>",
a->aa_rights & ACCESS_STREAMING ? "S" : "",
Expand All @@ -357,7 +357,7 @@ access_dump_a(access_t *a)
a->aa_rights & ACCESS_RECORDER ? "R" : "",
a->aa_rights & ACCESS_ADMIN ? "*" : "",
a->aa_conn_limit,
a->aa_chmin, a->aa_chmax,
(long long)a->aa_chmin, (long long)a->aa_chmax,
a->aa_match ? ", matched" : "");

if (a->aa_profiles) {
Expand Down Expand Up @@ -1295,13 +1295,15 @@ const idclass_t access_entry_class = {
.off = offsetof(access_entry_t, ae_conn_limit),
},
{
.type = PT_U32,
.type = PT_S64,
.intsplit = CHANNEL_SPLIT,
.id = "channel_min",
.name = "Min Channel Num",
.off = offsetof(access_entry_t, ae_chmin),
},
{
.type = PT_U32,
.type = PT_S64,
.intsplit = CHANNEL_SPLIT,
.id = "channel_max",
.name = "Max Channel Num",
.off = offsetof(access_entry_t, ae_chmax),
Expand Down
8 changes: 4 additions & 4 deletions src/access.h
Expand Up @@ -70,8 +70,8 @@ typedef struct access_entry {
int ae_webui;
int ae_admin;

uint32_t ae_chmin;
uint32_t ae_chmax;
uint64_t ae_chmin;
uint64_t ae_chmax;

struct channel_tag *ae_chtag;
LIST_ENTRY(access_entry) ae_channel_tag_link;
Expand All @@ -89,8 +89,8 @@ typedef struct access {
uint32_t aa_rights;
htsmsg_t *aa_profiles;
htsmsg_t *aa_dvrcfgs;
uint32_t aa_chmin;
uint32_t aa_chmax;
uint64_t aa_chmin;
uint64_t aa_chmax;
htsmsg_t *aa_chtags;
int aa_match;
uint32_t aa_conn_limit;
Expand Down
50 changes: 36 additions & 14 deletions src/api/api_channel.c
Expand Up @@ -25,21 +25,28 @@
#include "access.h"
#include "api.h"

static void
api_channel_key_val(htsmsg_t *dst, const char *key, const char *val)
{
htsmsg_t *e = htsmsg_create_map();
htsmsg_add_str(e, "key", key);
htsmsg_add_str(e, "val", val ?: "");
htsmsg_add_msg(dst, NULL, e);
}

// TODO: this will need converting to an idnode system
static int
api_channel_list
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
channel_t *ch;
htsmsg_t *l, *e;
htsmsg_t *l;

l = htsmsg_create_list();
pthread_mutex_lock(&global_lock);
CHANNEL_FOREACH(ch) {
e = htsmsg_create_map();
htsmsg_add_str(e, "key", idnode_uuid_as_str(&ch->ch_id));
htsmsg_add_str(e, "val", channel_get_name(ch));
htsmsg_add_msg(l, NULL, e);
if (!channel_access(ch, perm, 0)) continue;
api_channel_key_val(l, idnode_uuid_as_str(&ch->ch_id), channel_get_name(ch));
}
pthread_mutex_unlock(&global_lock);
*resp = htsmsg_create_map();
Expand All @@ -55,7 +62,8 @@ api_channel_grid
channel_t *ch;

CHANNEL_FOREACH(ch)
idnode_set_add(ins, (idnode_t*)ch, &conf->filter);
if (channel_access(ch, perm, 1))
idnode_set_add(ins, (idnode_t*)ch, &conf->filter);
}

static int
Expand All @@ -82,14 +90,19 @@ api_channel_tag_list
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
channel_tag_t *ct;
htsmsg_t *l, *e;
htsmsg_t *l;

l = htsmsg_create_list();
TAILQ_FOREACH(ct, &channel_tags, ct_link) {
e = htsmsg_create_map();
htsmsg_add_str(e, "key", idnode_uuid_as_str(&ct->ct_id));
htsmsg_add_str(e, "val", ct->ct_name);
htsmsg_add_msg(l, NULL, e);
if (perm->aa_chtags) {
htsmsg_field_t *f;
HTSMSG_FOREACH(f, perm->aa_chtags) {
ct = channel_tag_find_by_uuid(htsmsg_field_get_str(f) ?: "");
if (ct)
api_channel_key_val(l, idnode_uuid_as_str(&ct->ct_id), ct->ct_name);
}
} else {
TAILQ_FOREACH(ct, &channel_tags, ct_link)
api_channel_key_val(l, idnode_uuid_as_str(&ct->ct_id), ct->ct_name);
}
*resp = htsmsg_create_map();
htsmsg_add_msg(*resp, "entries", l);
Expand All @@ -102,8 +115,17 @@ api_channel_tag_grid
{
channel_tag_t *ct;

TAILQ_FOREACH(ct, &channel_tags, ct_link)
idnode_set_add(ins, (idnode_t*)ct, &conf->filter);
if (perm->aa_chtags) {
htsmsg_field_t *f;
HTSMSG_FOREACH(f, perm->aa_chtags) {
ct = channel_tag_find_by_uuid(htsmsg_field_get_str(f) ?: "");
if (ct)
idnode_set_add(ins, (idnode_t*)ct, &conf->filter);
}
} else {
TAILQ_FOREACH(ct, &channel_tags, ct_link)
idnode_set_add(ins, (idnode_t*)ct, &conf->filter);
}
}

static int
Expand Down
2 changes: 1 addition & 1 deletion src/api/api_epg.c
Expand Up @@ -422,7 +422,7 @@ api_epg_grid

/* Query the EPG */
pthread_mutex_lock(&global_lock);
epg_query(&eq);
epg_query(&eq, perm);

/* Build response */
start = MIN(eq.entries, start);
Expand Down
21 changes: 14 additions & 7 deletions src/channels.c
Expand Up @@ -309,14 +309,12 @@ const idclass_t channel_class = {
.ic_get_title = channel_class_get_title,
.ic_delete = channel_class_delete,
.ic_properties = (const property_t[]){
#if 0
{
.type = PT_BOOL,
.id = "enabled",
.name = "Enabled",
.off = offsetof(channel_t, ch_enabled),
},
#endif
{
.type = PT_STR,
.id = "name",
Expand Down Expand Up @@ -417,7 +415,7 @@ channel_find_by_name ( const char *name )
if (name == NULL)
return NULL;
CHANNEL_FOREACH(ch)
if (!strcmp(channel_get_name(ch), name))
if (ch->ch_enabled && !strcmp(channel_get_name(ch), name))
break;
return ch;
}
Expand Down Expand Up @@ -457,17 +455,23 @@ channel_find_by_number ( const char *no )
* Check if user can access the channel
*/
int
channel_access(channel_t *ch, access_t *a, const char *username)
channel_access(channel_t *ch, access_t *a, int disabled)
{
if (!ch)
return 0;

if (!disabled && !ch->ch_enabled)
return 0;

/* Channel number check */
if (ch && (a->aa_chmin || a->aa_chmax)) {
int chnum = channel_get_number(ch);
if (a->aa_chmin || a->aa_chmax) {
int64_t chnum = channel_get_number(ch);
if (chnum < a->aa_chmin || chnum > a->aa_chmax)
return 0;
}

/* Channel tag check */
if (ch && a->aa_chtags) {
if (a->aa_chtags) {
channel_tag_mapping_t *ctm;
htsmsg_field_t *f;
HTSMSG_FOREACH(f, a->aa_chtags) {
Expand Down Expand Up @@ -722,6 +726,9 @@ channel_create0
abort();
}

/* Defaults */
ch->ch_enabled = 1;

if (conf) {
ch->ch_load = 1;
idnode_load(&ch->ch_id, conf);
Expand Down
5 changes: 3 additions & 2 deletions src/channels.h
Expand Up @@ -43,12 +43,13 @@ typedef struct channel
idnode_t ch_id;

RB_ENTRY(channel) ch_link;

int ch_refcount;
int ch_zombie;
int ch_load;

/* Channel info */
int ch_enabled;
char *ch_name; // Note: do not access directly!
int64_t ch_number;
char *ch_icon;
Expand Down Expand Up @@ -176,7 +177,7 @@ htsmsg_t * channel_tag_class_get_list(void *o);

const char * channel_tag_get_icon(channel_tag_t *ct);

int channel_access(channel_t *ch, struct access *a, const char *username);
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);
Expand Down
1 change: 1 addition & 0 deletions src/dvr/dvr_autorec.c
Expand Up @@ -1047,6 +1047,7 @@ dvr_autorec_changed(dvr_autorec_entry_t *dae, int purge)
dvr_autorec_purge_spawns(dae, 1);

CHANNEL_FOREACH(ch) {
if (!ch->ch_enabled) continue;
RB_FOREACH(e, &ch->ch_epg_schedule, sched_link) {
if(autorec_cmp(dae, e))
dvr_entry_create_by_autorec(e, dae);
Expand Down
15 changes: 10 additions & 5 deletions src/epg.c
Expand Up @@ -2517,7 +2517,7 @@ static int _epg_sort_genre_descending ( const void *a, const void *b, void *eq )
}

epg_broadcast_t **
epg_query ( epg_query_t *eq )
epg_query ( epg_query_t *eq, access_t *perm )
{
channel_t *channel;
channel_tag_t *tag;
Expand All @@ -2542,20 +2542,25 @@ epg_query ( epg_query_t *eq )

/* Single channel */
if (channel && tag == NULL) {
_eq_add_channel(eq, channel);
if (channel_access(channel, perm, 0))
_eq_add_channel(eq, channel);

/* Tag based */
} else if (tag) {
channel_tag_mapping_t *ctm;
channel_t *ch2;
LIST_FOREACH(ctm, &tag->ct_ctms, ctm_tag_link) {
if(channel == NULL || ctm->ctm_channel == channel)
_eq_add_channel(eq, ctm->ctm_channel);
ch2 = ctm->ctm_channel;
if(ch2 == channel || channel == NULL)
if (channel_access(channel, perm, 0))
_eq_add_channel(eq, ch2);
}

/* All channels */
} else {
CHANNEL_FOREACH(channel)
_eq_add_channel(eq, channel);
if (channel_access(channel, perm, 0))
_eq_add_channel(eq, channel);
}

switch (eq->sort_dir) {
Expand Down
3 changes: 2 additions & 1 deletion src/epg.h
Expand Up @@ -22,6 +22,7 @@
#include <regex.h>
#include "settings.h"
#include "lang_str.h"
#include "access.h"

/*
* External forward decls
Expand Down Expand Up @@ -609,7 +610,7 @@ typedef struct epg_query {
uint32_t allocated;
} epg_query_t;

epg_broadcast_t **epg_query(epg_query_t *eq);
epg_broadcast_t **epg_query(epg_query_t *eq, access_t *perm);
void epg_query_free(epg_query_t *eq);

/* ************************************************************************
Expand Down
4 changes: 2 additions & 2 deletions src/htsp_server.c
Expand Up @@ -435,7 +435,7 @@ htsp_generate_challenge(htsp_connection_t *htsp)
static inline int
htsp_user_access_channel(htsp_connection_t *htsp, channel_t *ch)
{
return channel_access(ch, htsp->htsp_granted_access, htsp->htsp_username);
return channel_access(ch, htsp->htsp_granted_access, 0);
}

#define HTSP_CHECK_CHANNEL_ACCESS(htsp, ch)\
Expand Down Expand Up @@ -1189,7 +1189,7 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
return htsp_error("User does not have access");

/* Query */
epg_query(&eq);
epg_query(&eq, htsp->htsp_granted_access);

/* Create Reply */
out = htsmsg_create_map();
Expand Down
2 changes: 1 addition & 1 deletion src/http.c
Expand Up @@ -467,7 +467,7 @@ http_access_verify_channel(http_connection_t *hc, int mask,
if (access_verify2(hc->hc_access, mask))
return -1;

if (channel_access(ch, hc->hc_access, hc->hc_username))
if (channel_access(ch, hc->hc_access, 0))
res = 0;
return res;
}
Expand Down
2 changes: 1 addition & 1 deletion src/webui/simpleui.c
Expand Up @@ -189,7 +189,7 @@ page_simple(http_connection_t *hc,
eq.lang = strdup(lang);

//Note: force min/max durations for this interface to 0 and INT_MAX seconds respectively
epg_query(&eq);
epg_query(&eq, hc->hc_access);

c = eq.entries;

Expand Down
3 changes: 2 additions & 1 deletion src/webui/statedump.c
Expand Up @@ -59,7 +59,8 @@ dumpchannels(htsbuf_queue_t *hq)

CHANNEL_FOREACH(ch) {

htsbuf_qprintf(hq, "%s (%d)\n", channel_get_name(ch), channel_get_id(ch));
htsbuf_qprintf(hq, "%s%s (%d)\n", !ch->ch_enabled ? "[DISABLED] " : "",
channel_get_name(ch), channel_get_id(ch));
chnum = channel_get_number(ch);
if (channel_get_minor(chnum))
snprintf(chbuf, sizeof(chbuf), "%u.%u",
Expand Down
6 changes: 4 additions & 2 deletions src/webui/webui.c
Expand Up @@ -512,12 +512,14 @@ http_channel_list_playlist(http_connection_t *hc)
profile = profile_validate_name(http_arg_get(&hc->hc_req_args, "profile"));

CHANNEL_FOREACH(ch)
count++;
if (ch->ch_enabled)
count++;

chlist = malloc(count * sizeof(channel_t *));

CHANNEL_FOREACH(ch)
chlist[idx++] = ch;
if (ch->ch_enabled)
chlist[idx++] = ch;

assert(idx == count);

Expand Down

15 comments on commit da3d9ec

@ksooo
Copy link
Contributor

@ksooo ksooo commented on da3d9ec Nov 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting with this revision I'm no longer able to start new recordings/add timers using XBMC. Always getting "User does not have access". :-(

@perexg
Copy link
Contributor Author

@perexg perexg commented on da3d9ec Nov 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check ACL. You may use '--trace access' to log the access permissions to the log.

@ksooo
Copy link
Contributor

@ksooo ksooo commented on da3d9ec Nov 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many many lines containing; "2014-11-23 22:14:27.232 [ TRACE]:access: 192.168.178.25: [SAWR*], conn=0, chmin=0, chmax=0, profile=ANY, dvr=ANY, tag=ANY". No other trace output. What does this mean?

@bluzee
Copy link
Contributor

@bluzee bluzee commented on da3d9ec Nov 24, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this commit TVHGuide and TVHClient stop receiving EPG data.

@perexg
Copy link
Contributor Author

@perexg perexg commented on da3d9ec Nov 24, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue should be fixed in fe24184 . TVGuide uses HTSP protocol ? It seems so...

@bluzee
Copy link
Contributor

@bluzee bluzee commented on da3d9ec Nov 24, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, fixed now. Thank you.

@bluzee
Copy link
Contributor

@bluzee bluzee commented on da3d9ec Nov 27, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, one more thing. This also appears to be the commit where filter by channel tag stops working in the EPG web UI.

@perexg
Copy link
Contributor Author

@perexg perexg commented on da3d9ec Nov 27, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should work unless you have the tags marked as private or internal..

@ProfYaffle
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@perexg It seems that something's not right... I'm not running latest master, so can't test for the moment, but:

https://tvheadend.org/boards/5/topics/14191

@bluzee
Copy link
Contributor

@bluzee bluzee commented on da3d9ec Nov 28, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the tags are not private or internal. Seems to only affect the web ui.

@perexg
Copy link
Contributor Author

@perexg perexg commented on da3d9ec Nov 28, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you see all tags if you login as admin in the config grid and in the EPG combobox ?

OK. These two functions are in the chain to get the channel tags for EPG / webui. I'm probably blind, but I don't see any issue.

https://github.com/tvheadend/tvheadend/blob/master/src/api/api_channel.c#L88-L102
https://github.com/tvheadend/tvheadend/blob/master/src/channels.c#L1054-L1078

If the tag is not marked as private, the 'return 1' should be executed in channel_tag_access().

@Meindert66
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see all Tags if I login as admin in the config grid and in the EPG combobox.

But selecting a Cahnnel Tag as filter in the EPG gui results in a empty list.

@bluzee
Copy link
Contributor

@bluzee bluzee commented on da3d9ec Nov 28, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logged in as admin. There are no tags set as private or internal. With no tag filter set the EPG is fully populated with all channels. The tag filter box has all the tags listed. Selecting any of them results in empty EPG grid with a "No data to display" message. Selecting (Clear filter) repopulates the EPG with all channels.

@perexg
Copy link
Contributor Author

@perexg perexg commented on da3d9ec Nov 28, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 452ca85 . I thought that we're speaking about the combobox list not the EPG query result..

@bluzee
Copy link
Contributor

@bluzee bluzee commented on da3d9ec Nov 28, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for being vague. Confirm fixed. Thanks.

Please sign in to comment.