summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/input/input_smb.c269
1 files changed, 267 insertions, 2 deletions
diff --git a/src/input/input_smb.c b/src/input/input_smb.c
index 0ecc6dfba..8c1c62625 100644
--- a/src/input/input_smb.c
+++ b/src/input/input_smb.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: input_smb.c,v 1.6 2006/02/02 22:35:30 f1rmb Exp $
+ * $Id: input_smb.c,v 1.7 2006/02/04 12:08:22 miguelfreitas Exp $
*/
@@ -38,9 +38,14 @@
#include <locale.h>
#endif
+#define MAXFILES 65535
+
typedef struct {
input_class_t input_class;
xine_t *xine;
+
+ int mrls_allocated_entries;
+ xine_mrl_t **mrls;
} smb_input_class_t;
typedef struct {
@@ -155,6 +160,266 @@ static const char
return "smb";
}
+/*
+ * Sorting function, it comes from GNU fileutils package.
+ */
+#define S_N 0x0
+#define S_I 0x4
+#define S_F 0x8
+#define S_Z 0xC
+#define CMP 2
+#define LEN 3
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+static int _strverscmp(const char *s1, const char *s2) {
+ const unsigned char *p1 = (const unsigned char *) s1;
+ const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+ int state;
+ int diff;
+ static const unsigned int next_state[] = {
+ S_N, S_I, S_Z, S_N,
+ S_N, S_I, S_I, S_I,
+ S_N, S_F, S_F, S_F,
+ S_N, S_F, S_Z, S_Z
+ };
+ static const int result_type[] = {
+ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+ CMP, -1, -1, CMP, 1, LEN, LEN, CMP,
+ 1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
+ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+ CMP, 1, 1, CMP, -1, CMP, CMP, CMP,
+ -1, CMP, CMP, CMP
+ };
+
+ if(p1 == p2)
+ return 0;
+
+ c1 = *p1++;
+ c2 = *p2++;
+
+ state = S_N | ((c1 == '0') + (ISDIGIT(c1) != 0));
+
+ while((diff = c1 - c2) == 0 && c1 != '\0') {
+ state = next_state[state];
+ c1 = *p1++;
+ c2 = *p2++;
+ state |= (c1 == '0') + (ISDIGIT(c1) != 0);
+ }
+
+ state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT(c2) != 0))];
+
+ switch(state) {
+ case CMP:
+ return diff;
+
+ case LEN:
+ while(ISDIGIT(*p1++))
+ if(!ISDIGIT(*p2++))
+ return 1;
+
+ return ISDIGIT(*p2) ? -1 : diff;
+
+ default:
+ return state;
+ }
+}
+
+/*
+ * Wrapper to _strverscmp() for qsort() calls, which sort mrl_t type array.
+ */
+static int _sortfiles_default(const xine_mrl_t *s1, const xine_mrl_t *s2) {
+ return(_strverscmp(s1->mrl, s2->mrl));
+}
+
+
+static xine_mrl_t **smb_class_get_dir (input_class_t *this_gen,
+ const char *filename, int *nFiles) {
+
+ smb_input_class_t *this = (smb_input_class_t *) this_gen;
+ int (*func) () = _sortfiles_default;
+ unsigned int dir;
+ struct smbc_dirent *pdirent;
+ char current_path [XINE_PATH_MAX + 1];
+ char current_path_smb [XINE_PATH_MAX + 1];
+ int num_files=0;
+ if (filename != NULL && strlen(filename)>6){
+ snprintf(current_path, XINE_PATH_MAX, "%s",filename);
+ snprintf(current_path_smb, XINE_PATH_MAX, "%s/",current_path);
+ }else{
+ snprintf(current_path, XINE_PATH_MAX, "smb:/");
+ snprintf(current_path_smb, XINE_PATH_MAX, "smb://");
+ }
+
+ if ((dir = smbc_opendir(current_path_smb)) >= 0){
+ xine_mrl_t *dir_files = (xine_mrl_t *) xine_xmalloc(sizeof(xine_mrl_t) * MAXFILES);
+ xine_mrl_t *norm_files = (xine_mrl_t *) xine_xmalloc(sizeof(xine_mrl_t) * MAXFILES);
+ int num_dir_files=0;
+ int num_norm_files=0;
+ while ((pdirent = smbc_readdir(dir)) != NULL){
+ if (pdirent->smbc_type == SMBC_WORKGROUP){
+ dir_files[num_dir_files].link = NULL;
+ dir_files[num_dir_files].type = mrl_file | mrl_file_directory;
+ dir_files[num_dir_files].origin = strdup(current_path);
+ dir_files[num_dir_files].mrl = (char *) xine_xmalloc(
+ strlen(current_path) + 1 + strlen(pdirent->name) + 1);
+ sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, pdirent->name);
+ dir_files[num_dir_files].size = pdirent->dirlen;
+ num_dir_files ++;
+ }else if (pdirent->smbc_type == SMBC_SERVER){
+ if (num_dir_files == 0) {
+ dir_files[num_dir_files].link = NULL;
+ dir_files[num_dir_files].type = mrl_file | mrl_file_directory;
+ dir_files[num_dir_files].origin = strdup("smb:/");
+ dir_files[num_dir_files].mrl = (char *) xine_xmalloc(strlen("smb:/") + 4);
+ sprintf(dir_files[num_dir_files].mrl, "%s/%s", "smb:/", "..");
+ dir_files[num_dir_files].size = pdirent->dirlen;
+ num_dir_files ++;
+ }
+ dir_files[num_dir_files].link = NULL;
+ dir_files[num_dir_files].type = mrl_file | mrl_file_directory;
+ dir_files[num_dir_files].origin = strdup("smb:/");
+ dir_files[num_dir_files].mrl =
+ (char *) xine_xmalloc(strlen("smb:/") + 1 + strlen(pdirent->name) + 1);
+ sprintf(dir_files[num_dir_files].mrl, "%s/%s", "smb:/", pdirent->name);
+ dir_files[num_dir_files].size = pdirent->dirlen;
+ num_dir_files ++;
+ } else if (pdirent->smbc_type == SMBC_FILE_SHARE){
+ if (num_dir_files == 0) {
+ dir_files[num_dir_files].link = NULL;
+ dir_files[num_dir_files].type = mrl_file | mrl_file_directory;
+ dir_files[num_dir_files].origin = strdup(current_path);
+ dir_files[num_dir_files].mrl = (char *) xine_xmalloc(
+ strlen(current_path) + 3);
+ sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, "..");
+ dir_files[num_dir_files].type |= mrl_file_directory;
+ dir_files[num_dir_files].size = pdirent->dirlen;
+ num_dir_files ++;
+ }
+ if (pdirent->name[strlen(pdirent->name)-1]!='$'){
+ dir_files[num_dir_files].link = NULL;
+ dir_files[num_dir_files].type = mrl_file | mrl_file_directory;
+ dir_files[num_dir_files].origin = strdup(current_path);
+ dir_files[num_dir_files].mrl = (char *) xine_xmalloc(
+ strlen(current_path) + 1 + strlen(pdirent->name) + 1);
+ sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, pdirent->name);
+ dir_files[num_dir_files].size = pdirent->dirlen;
+ num_dir_files ++;
+ }
+ } else if (pdirent->smbc_type == SMBC_DIR){
+ dir_files[num_dir_files].link = NULL;
+ dir_files[num_dir_files].type = mrl_file | mrl_file_directory;
+ dir_files[num_dir_files].origin = strdup(current_path);
+ dir_files[num_dir_files].mrl =
+ (char *) xine_xmalloc(strlen(current_path) + 1 + strlen(pdirent->name) + 1);
+ sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, pdirent->name);
+ dir_files[num_dir_files].size = pdirent->dirlen;
+ num_dir_files ++;
+ }else if (pdirent->smbc_type == SMBC_FILE){
+ norm_files[num_norm_files].link = NULL;
+ norm_files[num_norm_files].type = mrl_file | mrl_file_normal;
+ norm_files[num_norm_files].origin = strdup(current_path);
+ norm_files[num_norm_files].mrl =
+ (char *) xine_xmalloc(strlen(current_path) + 1 + strlen(pdirent->name) + 1);
+ sprintf(norm_files[num_norm_files].mrl, "%s/%s", current_path, pdirent->name);
+ norm_files[num_norm_files].size = pdirent->dirlen;
+ num_norm_files ++;
+ }
+ }
+ smbc_closedir(dir);
+
+ if (num_dir_files == 0) {
+ dir_files[num_dir_files].link = NULL;
+ dir_files[num_dir_files].origin = strdup(current_path);
+ dir_files[num_dir_files].mrl = (char *) xine_xmalloc(strlen(current_path) + 4);
+ sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, "..");
+ dir_files[num_dir_files].type = mrl_file | mrl_file_directory;
+ dir_files[num_dir_files].size = 0;
+ num_dir_files ++;
+ }
+
+ /*
+ * Sort arrays
+ */
+ if(num_dir_files)
+ qsort(dir_files, num_dir_files, sizeof(xine_mrl_t), func);
+
+ if(num_norm_files)
+ qsort(norm_files, num_norm_files, sizeof(xine_mrl_t), func);
+
+ /*
+ * Add directories entries
+ */
+ int i;
+ for(i = 0; i < num_dir_files; i++) {
+ if (num_files >= this->mrls_allocated_entries) {
+ ++this->mrls_allocated_entries;
+ this->mrls = realloc(this->mrls,
+ (this->mrls_allocated_entries+1) * sizeof(xine_mrl_t*));
+ this->mrls[num_files] = (xine_mrl_t *) xine_xmalloc(sizeof(xine_mrl_t));
+ }else
+ memset(this->mrls[num_files], 0, sizeof(xine_mrl_t));
+
+ MRL_DUPLICATE(&dir_files[i], this->mrls[num_files]);
+
+ num_files++;
+ }
+
+ /*
+ * Add other files entries
+ */
+ for(i = 0; i < num_norm_files; i++) {
+ if(num_files >= this->mrls_allocated_entries) {
+ ++this->mrls_allocated_entries;
+ this->mrls = realloc(this->mrls,
+ (this->mrls_allocated_entries+1) * sizeof(xine_mrl_t*));
+ this->mrls[num_files] = (xine_mrl_t *) xine_xmalloc(sizeof(xine_mrl_t));
+ }else
+ memset(this->mrls[num_files], 0, sizeof(xine_mrl_t));
+
+ MRL_DUPLICATE(&norm_files[i], this->mrls[num_files]);
+
+ num_files++;
+ }
+
+ /* Some cleanups before leaving */
+ for(i = num_dir_files; i == 0; i--)
+ MRL_ZERO(&dir_files[i]);
+ free(dir_files);
+
+ for(i = num_norm_files; i == 0; i--)
+ MRL_ZERO(&norm_files[i]);
+ free(norm_files);
+ }else {
+ xprintf (this->xine, XINE_VERBOSITY_DEBUG,
+ "input_smb: smbc_opendir(\"%s\") failed: %d - %s\n",
+ current_path, errno, strerror(errno));
+ *nFiles = 0;
+ return NULL;
+ }
+
+ /*
+ * Inform caller about files found number.
+ */
+ *nFiles = num_files;
+
+ /*
+ * Freeing exceeded mrls if exists.
+ */
+ while(this->mrls_allocated_entries > num_files) {
+ MRL_ZERO(this->mrls[this->mrls_allocated_entries - 1]);
+ free(this->mrls[this->mrls_allocated_entries--]);
+ }
+
+ /*
+ * This is useful to let UI know where it should stops ;-).
+ */
+ this->mrls[num_files] = NULL;
+
+ return this->mrls;
+}
+
static int
smb_plugin_get_optional_data (input_plugin_t *this_gen,
void *data, int data_type)
@@ -253,7 +518,7 @@ static void
this->input_class.get_instance = smb_class_get_instance;
this->input_class.get_identifier = smb_class_get_identifier;
this->input_class.get_description = smb_class_get_description;
- this->input_class.get_dir = NULL;
+ this->input_class.get_dir = smb_class_get_dir;
this->input_class.get_autoplay_list = NULL;
this->input_class.dispose = smb_class_dispose;
this->input_class.eject_media = NULL;