📄 msdl.c
字号:
/*********************************************************************** * msdl.c: download management functions *********************************************************************** * Copyright (C) 2007 metro <me_t_ro@yahoo.com> * * This file is part of msdl, media stream downloader * See README for program usage and information. * See COPYING for license information. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * ***********************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <getopt.h>#include <sys/time.h>#include "msdl.h"#include "msdllib.h"#include "display.h"#include "progress.h"#include "network.h"#include "mmst.h"#include "mmsh.h"#include "http.h"#include "ftp.h"#include "rtsp.h"struct download_opts_t *set_dlopts_from_options(struct options_t *options, struct download_opts_t *dlopts);static char *create_local_file_name(char *target_str,struct options_t *options);static int download_target(char *target_str, struct options_t *options,struct dlresult_t *result, char **local_name);static int prepare_download(char *target_str,struct options_t *options, struct url_t **url_ret,struct download_opts_t **dlopts_ret, char **local_name);static int do_download(const char *local_name,struct url_t *url,struct download_opts_t *dlopts);static int streaming_download(const char *local_file,struct url_t *url, struct download_opts_t *dlopts);static void display_protocol(struct stream_t *stream);static int filename_cmp(void *a,void *b);static int is_metafile(char *name);static int get_url_list_from_file(char *filename,struct list_h **ret);const char default_file_name_for_empty[] = "file";/* * meta_f ... 1 --> always metafile * 0 --> don't know, judge from name * -1 --> NEVER. */struct target_t *new_target_t(char *name,int meta_f){ struct target_t *t = xmalloc(sizeof(struct target_t)); t->target_name = strdup(name); t->metafile_f = meta_f; return t;}void free_target_t(struct target_t *t){ if(!t) { return; } free(t->target_name); free(t);}struct options_t *new_options_t(void){ struct options_t *opt = xmalloc(sizeof(struct options_t)); memset(opt,0,sizeof(struct options_t)); return opt;}void free_options_t(struct options_t *opt){ if(!opt) { return; } if(opt->protocol) free(opt->protocol); if(opt->local_filename) free(opt->local_filename); if(opt->logfile) free(opt->logfile); if(opt->username) free(opt->username); if(opt->password) free(opt->password); if(opt->http_proxy) free(opt->http_proxy); if(opt->speed) free(opt->speed); if(opt->range) free(opt->range); if(opt->byterange) free(opt->byterange); free_list_h(opt->targets,(void (*)(void *))free_target_t); free(opt);}struct download_opts_t *new_download_opts_t(void){ struct download_opts_t *dlopts = xmalloc(sizeof(struct download_opts_t)); memset(dlopts,0,sizeof(struct download_opts_t)); return dlopts;}struct download_opts_t *set_dlopts_from_options(struct options_t *options, struct download_opts_t *dlopts){ /* set download options, such as bandwidth, some mode, etc. !!!! CAUTION !!!! these options are applied to all download in target list. */ if((options == NULL) || (dlopts == NULL)) { return NULL; } if(options->bandwidth) { dlopts->bandwidth = options->bandwidth; } if(options->no_passive_ftp_f) { dlopts->no_passive_ftp = 1; } if(options->speed) { dlopts->speed = strdup(options->speed); } if(options->range) { dlopts->range = strdup(options->range); } if(options->byterange) { dlopts->byterange = strdup(options->byterange); } if(options->auto_retry_times) { dlopts->auto_retry = options->auto_retry_times; } if(options->resume) { dlopts->resume_download = 1; } if(options->username) { dlopts->username = strdup(options->username); } if(options->password) { dlopts->password = strdup(options->password); } if(options->http_proxy) { dlopts->http_proxy = strdup(options->http_proxy); } return dlopts;}void free_download_opts_t(struct download_opts_t *dlopts){ if(!dlopts) { return; } if(dlopts->speed) free(dlopts->speed); if(dlopts->range) free(dlopts->range); if(dlopts->byterange) free(dlopts->byterange); if(dlopts->username) free(dlopts->username); if(dlopts->password) free(dlopts->password); free(dlopts);}struct dlresult_t *new_dlresult_t(void){ struct dlresult_t *dlr = xmalloc(sizeof(struct dlresult_t)); memset(dlr,0,sizeof(struct dlresult_t)); return dlr;}void free_dlresult_t(struct dlresult_t *dlr){ if(!dlr) { return; } if(dlr->success_list) free_list_h(dlr->success_list,free); if(dlr->failed_list) free_list_h(dlr->failed_list,free); free(dlr);}/* * take 2 urls, a and b. only use filename at the end of url. * return value: 0 ... same file * : non 0 ... file name differs */static int filename_cmp(void *a,void *b){ char *s = (char *)a,*t = (char *)b; s = strrchr(s,'/') + 1; t = strrchr(t,'/') + 1; return strcmp(s,t);}/* * files with these extensions are regarded as metafiles. */char *metafile_prefixes[] = { /* Windows Media metafiles */ "asx", "wvx", "wax", /* Real Audio metafiles */ "ram", "rpm", "smi",};char *metafile_starts[] = { "meta",};/* * judge if url 'name' is windows/real media metafile or not, from * metafile_prefixes described above * return value: 0 ... not * 1 ... yes it is. */static int is_metafile(char *name){ int i = 0; char *p = NULL; if((p = strrchr(name,'.'))) { p++; for(i = 0; i < sizeof(metafile_prefixes)/sizeof(char *) ; i++) { if(!strcasecmp(metafile_prefixes[i],p)) return 1; } } if((p = strrchr(name,'/'))) { p++; for(i = 0; i < sizeof(metafile_starts)/sizeof(char *) ; i++) { if(!strncasecmp(metafile_starts[i],p,strlen(metafile_starts[i]))) return 1; } } return 0;}/* * get string(url) list from file 'filename' * for not downloading same URLs again and again, * this function returns list via "uniq" filter. * * @ret string list ... success * NULL ... no url in file * * return value: count ... URLs appear in the file * -1 ... could not open file */static int get_url_list_from_file(char *filename,struct list_h **ret){ FILE *localfp = NULL; struct list_h *url_list = NULL; int linesize = BUFSIZE_1K; char *line = xmalloc(linesize); /* 1024 bytes default */ char *p = NULL; char *sep = NULL; int url_len = 0; int url_count = 0; /* try to download first url in the list --> maybe playlist contain same url twice */ if((localfp = fopen(filename,"rb")) == NULL) { display(MSDL_ERR,"cannot open file %s\n",filename); goto open_failed; } while(fgets(line,linesize,localfp)) { while((line[strlen(line) - 1] != '\n')) { /* didn't read the whole line */ linesize += BUFSIZE_1K; line = xrealloc(line,linesize); if(fgets(line + strlen(line),BUFSIZE_1K,localfp) == NULL) { /* error or EOF */ break; } } p = line; while((sep = strstr(p,"://"))) { /* contains url string */ /* protocol is alphabet */ for(sep--; sep >= p && isalpha(*sep) ; sep--); sep++; for(url_len = 0; is_url_valid_char(sep[url_len]); url_len++); sep[url_len] = '\0'; /* for not downloading same file again and again */ if(sep[url_len - 1] != '/') { /*ignore directories */ if(search_list_h(url_list,sep,filename_cmp) == NULL) { /* same file not found */ list_h_append(&url_list,strdup(sep)); url_count++; } else { display(MSDL_VER,"file: <%s> is not uniq, ignore this\n", strrchr(sep,'/') + 1); } } p = &(sep[url_len]) + 1; } } free(line); fclose(localfp); *ret = url_list; return url_count; open_failed: free(line); *ret = NULL; return -1;}/* * main download manager function * * 'target' is url or local file which contains url(s) to download * * return value: number of files which successfully donwloaded * */int msdl(struct target_t *target,struct options_t *options,struct dlresult_t *result){ int downloaded_files_count = 0; int ret; /* set urls to download. */ if(strstr(target->target_name,"://")) { /* network file case */ char *local_filename = NULL; ret = download_target(target->target_name, options, result, &local_filename); /* local filename will be returned */ /* we got metafile from network --> have to download what's inside */ if((target->metafile_f != FORCE_NOT_METAFILE) && /* -1 is no-metafile flag */ (is_metafile(target->target_name) || target->metafile_f == IS_METAFILE) && (ret >= 0)) { /* download must be success(1) or already done(0)*/ struct target_t *new_target = NULL; /* recursive download */ /* DO NOT DO RECURSIVE AGAIN*/ new_target = new_target_t(local_filename,FORCE_NOT_METAFILE); /* rcursive download file */ downloaded_files_count += msdl(new_target,options,result); free_target_t(new_target); } if(local_filename) free(local_filename); } else { /* file list (local file) */ struct list_h *p = NULL; /* iterator */ struct list_h *target_str_list = NULL; /* string */ int ret = 0; ret = get_url_list_from_file(target->target_name,&target_str_list); if(ret < 0) { /*could not open file*/ return 0; } else if(ret == 0) { display(MSDL_ERR,"input file \"%s\" does not contain any url\n",target->target_name); return 0; } /* download each files the list*/ for(p = target_str_list ; p ; p = p->next) { char *target_str = p->p; struct target_t *target_in_file = NULL; /* create file which contains downloaded data. */ target_in_file = new_target_t(target_str,FORCE_NOT_METAFILE); downloaded_files_count += msdl(target_in_file,options,result); free_target_t(target_in_file); } free_list_h(target_str_list,free); } return downloaded_files_count;}/* * create local file name string from target_str and options->local_filename * return value: local file name to save, from target_str or options->local_filename * NULL if invalid. */static char *create_local_file_name(char *target_str,struct options_t *options){ char *local_filename = NULL; if(options->local_filename && strcmp(options->local_filename,"")) { local_filename = strdup(options->local_filename); /* cannot use options->local_filename again */ strcpy(options->local_filename,""); } else { char *p = strrchr(target_str,'/'); if(p && p[1] != '\0') { /* do not allow local_filename to be "" (p[0] == '/' now)*/ local_filename = strdup(p + 1); } } return local_filename;}/* * download target_str ==> local_save_file * and append success/failure results to results list. * return value: 1 (do_download() return) ... success * 0 ... file already downloaded, and nothing to do * -1 ... faliure */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -