* now search all srvtypes and add all srvs of all srvtypes to the
[vlc.git] / modules / access / slp.c
1 /*****************************************************************************
2  * slp.c: SLP access plugin
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: slp.c,v 1.5 2003/01/21 17:34:03 lool Exp $
6  *
7  * Authors: Loïc Minier <lool@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28 #include <vlc/input.h>
29
30 #include <vlc_playlist.h>
31
32 #include <slp.h>
33
34 /*****************************************************************************
35  * Local prototypes
36  *****************************************************************************/
37 static int  Open  ( vlc_object_t * );
38 static void Close ( vlc_object_t * );
39 static ssize_t Read  ( input_thread_t *, byte_t *, size_t );
40
41 static int  Init  ( vlc_object_t * );
42 static void End   ( vlc_object_t * );
43 static int  Demux ( input_thread_t * );
44
45 /*****************************************************************************
46  * Module descriptor
47  *****************************************************************************/
48
49 #define SRVTYPE_TEXT "SLP service type"
50 #define SRVTYPE_LONGTEXT "The service type string for SLP queries, " \
51                          "including the authority string (if any) for the " \
52                          "request. May not be empty"
53 #define SCOPELIST_TEXT "SLP scopes list"
54 #define SCOPELIST_LONGTEXT "This string is a comma separated list of scope " \
55                            "names or empty if you want to use the default "  \
56                            "scopes; it is used in all SLP queries"
57 #define NAMINGAUTHORITY_TEXT "SLP naming authority"
58 #define NAMINGAUTHORITY_LONGTEXT "This string is a list of naming " \
59                                  "authorities to search. Use \"*\" for all " \
60                                  "and the empty string for the default of " \
61                                  "IANA"
62 #define FILTER_TEXT "SLP LDAP filter"
63 #define FILTER_LONGTEXT "This is a query formulated of attribute pattern " \
64                         "matching expressions in the form of an LDAPv3 "   \
65                         "search filter or empty for all answers"
66 #define LANG_TEXT "language asked in SLP requests"
67 #define LANG_LONGTEXT "RFC 1766 Language Tag for the natural language " \
68                       "locale of requests, leave empty to use the "     \
69                       "default locale"
70
71 vlc_module_begin();
72     set_description( _("SLP access module") );
73     add_category_hint( N_("slp"), NULL );
74 /*    add_string( "slp-srvtype", "service:vls.services.videolan.org:udpm",
75                 NULL, SRVTYPE_TEXT, SRVTYPE_LONGTEXT ); */
76     add_string( "slp-scopelist", "", NULL, SCOPELIST_TEXT,
77                 SCOPELIST_LONGTEXT );
78     add_string( "slp-namingauthority", "*", NULL, NAMINGAUTHORITY_TEXT,
79                 NAMINGAUTHORITY_LONGTEXT );
80     add_string( "slp-filter", "", NULL, FILTER_TEXT, FILTER_LONGTEXT );
81     add_string( "slp-lang", "", NULL, LANG_TEXT, LANG_LONGTEXT );
82     add_submodule();
83         set_capability( "access", 0 );
84         set_callbacks( Open, Close );
85     add_submodule();
86         add_shortcut( "demux_slp" );
87         set_capability( "demux", 0 );
88         set_callbacks( Init, End );
89 vlc_module_end();
90
91 /*****************************************************************************
92  * SrvUrlCallback: adds an entry to the playlist
93  *****************************************************************************/
94 static SLPBoolean SrvUrlCallback( SLPHandle slph_slp,
95                            const char * psz_srvurl,
96                            uint16_t i_lifetime,
97                            SLPError slpe_errcode,
98                            void * p_cookie )
99 {
100     input_thread_t * p_input = (input_thread_t  *)p_cookie;
101     playlist_t * p_playlist;
102     char psz_item[42] = "udp:@";
103     char * psz_s;
104
105     /* our callback was only called to tell us there's nothing more to read */
106     if( slpe_errcode == SLP_LAST_CALL )
107     {
108         return SLP_TRUE;
109     }
110
111     /* or there was a problem with getting the data we requested */
112     if( (slpe_errcode != SLP_OK) )
113     {
114         msg_Err( p_input,
115                  "SrvUrlCallback got an error %i with URL %s",
116                  slpe_errcode,
117                  psz_srvurl );
118         return SLP_TRUE;
119     }
120
121     /* search the returned address after a double-slash */
122     psz_s = strstr( psz_srvurl, "//" );
123     /* skip the slashes */
124     psz_s = &psz_s[2];
125     if( psz_s == NULL )
126     {
127         msg_Err( (input_thread_t *)p_input,
128                  "SrvUrlCallback got a NULL string if your libslp" );
129         return SLP_TRUE;
130     }
131     /* add udp:@ in front of the address */
132     psz_s = strncat( psz_item,
133                      psz_s,
134                      sizeof(psz_item) - strlen(psz_item) - 1 );
135
136     /* search the main playlist object */
137     p_playlist = vlc_object_find( (input_thread_t *)p_input,
138                                   VLC_OBJECT_PLAYLIST,
139                                   FIND_ANYWHERE );
140     if( p_playlist == NULL )
141     {
142         msg_Warn( (input_thread_t *)p_input,
143                   "could not find playlist, not adding entries" );
144         return SLP_TRUE;
145     }
146
147     playlist_Add( p_playlist, psz_s,
148                   PLAYLIST_APPEND,
149                   PLAYLIST_END );
150     vlc_object_release( (vlc_object_t *)p_playlist );
151
152     msg_Info( (input_thread_t *)p_input,
153              "added « %s » (lifetime %i) to playlist",
154              psz_srvurl,
155              i_lifetime );
156
157     return SLP_TRUE;
158 }
159
160 /*****************************************************************************
161  * SrvTypeCallback: searchs all servers of a certain type
162  *****************************************************************************/
163 static SLPBoolean SrvTypeCallback( SLPHandle slph_slp,
164                            const char * psz_srvurl,
165                            SLPError slpe_errcode,
166                            void * p_cookie )
167 {
168     input_thread_t * p_input = (input_thread_t  *)p_cookie;
169     SLPError slpe_result;
170     SLPHandle slph_slp2;
171
172     /* our callback was only called to tell us there's nothing more to read */
173     if( slpe_errcode == SLP_LAST_CALL )
174     {
175         return SLP_TRUE;
176     }
177
178     /* or there was a problem with getting the data we requested */
179     if( slpe_errcode != SLP_OK )
180     {
181         msg_Err( p_input,
182                  "SrvTypeCallback got an error %i with URL %s",
183                  slpe_errcode,
184                  psz_srvurl );
185         return SLP_TRUE;
186     }
187
188     /* get a new handle to the library */
189     if( SLPOpen( config_GetPsz( p_input, "slp-lang" ),
190                  SLP_FALSE,                              /* synchronous ops */
191                  &slph_slp2 ) == SLP_OK )
192     {
193         /* search for services */
194         slpe_result = SLPFindSrvs( slph_slp2,
195                                    psz_srvurl,
196                                    config_GetPsz( p_input, "slp-scopelist" ),
197                                    config_GetPsz( p_input, "slp-filter" ),
198                                    SrvUrlCallback,
199                                    p_input );
200
201         SLPClose( slph_slp2 );
202
203         if( slpe_result != SLP_OK )
204         {
205             msg_Err( p_input,
206                      "SLPFindSrvs error %i finding servers of type %s",
207                      slpe_result,
208                      psz_srvurl );
209         }
210     }
211
212     return SLP_TRUE;
213 }
214
215 /*****************************************************************************
216  * Open: initialize library for the access module
217  *****************************************************************************/
218 static int Open( vlc_object_t * p_this )
219 {
220     input_thread_t * p_input = (input_thread_t *)p_this;
221     SLPError         slpe_result;
222     SLPHandle        slph_slp;
223     playlist_t *     p_playlist;
224
225     /* remove the "slp:" entry of the playlist */
226     p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
227                                                  FIND_ANYWHERE );
228     if( !p_playlist )
229     {
230         msg_Warn( p_input, "hey I can't find the main playlist, I need it" );
231         return VLC_FALSE;
232     }
233
234     p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
235     vlc_object_release( (vlc_object_t *)p_playlist );
236
237     /* get a new handle to the library */
238     if( SLPOpen( config_GetPsz( p_input, "slp-lang" ),
239                  SLP_FALSE,                              /* synchronous ops */
240                  &slph_slp ) == SLP_OK )
241     {
242         /* search all service types */
243         slpe_result =
244             SLPFindSrvTypes( slph_slp,
245                              config_GetPsz( p_input, "slp-namingauthority" ),
246                              config_GetPsz( p_input, "slp-scopelist" ),
247                              SrvTypeCallback,
248                              p_input );
249         /* we're done, clean up */
250         SLPClose( slph_slp );
251     }
252
253     if( !p_input->psz_demux || !*p_input->psz_demux )
254     {
255         p_input->psz_demux = "demux_slp";
256     }
257
258     p_input->pf_read = Read;
259     p_input->pf_set_program = NULL;
260     p_input->pf_set_area = NULL;
261     p_input->pf_seek = NULL;
262
263     vlc_mutex_lock( &p_input->stream.stream_lock );
264     p_input->stream.b_pace_control = VLC_FALSE;
265     p_input->stream.b_seekable = VLC_FALSE;
266     p_input->stream.b_connected = VLC_TRUE;
267     p_input->stream.p_selected_area->i_tell = 0;
268     p_input->stream.p_selected_area->i_size = 0;
269     p_input->stream.i_method = INPUT_METHOD_SLP;
270     vlc_mutex_unlock( &p_input->stream.stream_lock );
271     p_input->i_mtu = 0;
272
273     return VLC_SUCCESS;
274 }
275
276 /*****************************************************************************
277  * Close: close access
278  *****************************************************************************/
279 static void Close( vlc_object_t * p_this )
280 {
281     return;
282 }
283
284 /*****************************************************************************
285  * Read: should fill but zeroes the buffer
286  *****************************************************************************/
287 static ssize_t Read  ( input_thread_t *p_input, byte_t *p_buffer, size_t s )
288 {
289     memset( p_buffer, 0, s );
290     return s;
291 }
292
293 /*****************************************************************************
294  * Init: initialize demux
295  *****************************************************************************/
296 static int Init ( vlc_object_t *p_this )
297 {
298     input_thread_t *p_input = (input_thread_t *)p_this;
299
300     if( p_input->stream.i_method != INPUT_METHOD_SLP )
301     {
302         return VLC_FALSE;
303     }
304
305     p_input->pf_demux  = Demux;
306     p_input->pf_rewind = NULL;
307
308     return VLC_SUCCESS;
309 }
310
311 /*****************************************************************************
312  * Demux: should demux but does nothing
313  *****************************************************************************/
314 static int Demux ( input_thread_t * p_input )
315 {
316     return 0;
317 }
318
319 /*****************************************************************************
320  * End: end demux
321  *****************************************************************************/
322 static void End ( vlc_object_t *p_this )
323 {
324     return;
325 }
326