1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2003-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(ct_ftp). 22 23%% API 24-export([get/3,put/3, open/1,close/1, send/2,send/3, 25 recv/2,recv/3, cd/2, ls/2, type/2, delete/2]). 26 27%% Callbacks 28-export([init/3,handle_msg/2,reconnect/2,terminate/2]). 29 30-include("ct_util.hrl"). 31 32-record(state,{ftp_pid,target_name}). 33 34-define(DEFAULT_PORT,21). 35 36%%%================================================================= 37%%% API 38 39put(KeyOrName,LocalFile,RemoteFile) -> 40 Fun = fun(Ftp) -> send(Ftp,LocalFile,RemoteFile) end, 41 open_and_do(KeyOrName,Fun). 42 43get(KeyOrName,RemoteFile,LocalFile) -> 44 Fun = fun(Ftp) -> recv(Ftp,RemoteFile,LocalFile) end, 45 open_and_do(KeyOrName,Fun). 46 47open(KeyOrName) -> 48 case ct_util:get_key_from_name(KeyOrName) of 49 {ok,node} -> 50 open(KeyOrName,"erlang","x"); 51 _ -> 52 case ct:get_config(KeyOrName) of 53 undefined -> 54 log(heading(open,KeyOrName),"Failed: ~tp\n", 55 [{not_available,KeyOrName}]), 56 {error,{not_available,KeyOrName}}; 57 _ -> 58 case ct:get_config({KeyOrName,username}) of 59 undefined -> 60 log(heading(open,KeyOrName),"Failed: ~tp\n", 61 [{not_available,{KeyOrName,username}}]), 62 {error,{not_available,{KeyOrName,username}}}; 63 Username -> 64 case ct:get_config({KeyOrName,password}) of 65 undefined -> 66 log(heading(open,KeyOrName),"Failed: ~tp\n", 67 [{not_available,{KeyOrName,password}}]), 68 {error,{not_available,{KeyOrName,password}}}; 69 Password -> 70 open(KeyOrName,Username,Password) 71 end 72 end 73 end 74 end. 75 76open(KeyOrName,Username,Password) -> 77 log(heading(open,KeyOrName),"",[]), 78 case ct:get_config({KeyOrName,ftp}) of 79 undefined -> 80 log(heading(open,KeyOrName),"Failed: ~tp\n", 81 [{not_available,{KeyOrName,ftp}}]), 82 {error,{not_available,{KeyOrName,ftp}}}; 83 Addr -> 84 ct_gen_conn:start(KeyOrName,full_addr(Addr),{Username,Password},?MODULE) 85 end. 86 87send(Connection,LocalFile) -> 88 send(Connection,LocalFile,filename:basename(LocalFile)). 89 90send(Connection,LocalFile,RemoteFile) -> 91 case get_handle(Connection) of 92 {ok,Pid} -> 93 call(Pid,{send,LocalFile,RemoteFile}); 94 Error -> 95 Error 96 end. 97 98recv(Connection,RemoteFile) -> 99 recv(Connection,RemoteFile,filename:basename(RemoteFile)). 100 101recv(Connection,RemoteFile,LocalFile) -> 102 case get_handle(Connection) of 103 {ok,Pid} -> 104 call(Pid,{recv,RemoteFile,LocalFile}); 105 Error -> 106 Error 107 end. 108 109cd(Connection,Dir) -> 110 case get_handle(Connection) of 111 {ok,Pid} -> 112 call(Pid,{cd,Dir}); 113 Error -> 114 Error 115 end. 116 117ls(Connection,Dir) -> 118 case get_handle(Connection) of 119 {ok,Pid} -> 120 call(Pid,{ls,Dir}); 121 Error -> 122 Error 123 end. 124 125type(Connection,Type) -> 126 case get_handle(Connection) of 127 {ok,Pid} -> 128 call(Pid,{type,Type}); 129 Error -> 130 Error 131 end. 132 133delete(Connection,File) -> 134 case get_handle(Connection) of 135 {ok,Pid} -> 136 call(Pid,{delete,File}); 137 Error -> 138 Error 139 end. 140 141close(Connection) -> 142 case get_handle(Connection) of 143 {ok,Pid} -> 144 ct_gen_conn:stop(Pid); 145 Error -> 146 Error 147 end. 148 149 150%%%================================================================= 151%%% Callback functions 152 153init(KeyOrName,{IP,Port},{Username,Password}) -> 154 case ftp_connect(IP,Port,Username,Password) of 155 {ok,FtpPid} -> 156 log(heading(init,KeyOrName), 157 "Opened ftp connection:\nIP: ~tp\nUsername: ~tp\nPassword: ~p\n", 158 [IP,Username,lists:duplicate(string:length(Password),$*)]), 159 {ok,FtpPid,#state{ftp_pid=FtpPid,target_name=KeyOrName}}; 160 Error -> 161 Error 162 end. 163 164ftp_connect(IP,Port,Username,Password) -> 165 _ = ftp:start(), 166 case ftp:start_service([{host,IP},{port,Port}]) of 167 {ok,FtpPid} -> 168 case ftp:user(FtpPid,Username,Password) of 169 ok -> 170 {ok,FtpPid}; 171 {error,Reason} -> 172 {error,{user,Reason}} 173 end; 174 {error,Reason} -> 175 {error,{open,Reason}} 176 end. 177 178handle_msg({send,LocalFile,RemoteFile},State) -> 179 log(heading(send,State#state.target_name), 180 "LocalFile: ~tp\nRemoteFile: ~tp\n",[LocalFile,RemoteFile]), 181 Result = ftp:send(State#state.ftp_pid,LocalFile,RemoteFile), 182 {Result,State}; 183handle_msg({recv,RemoteFile,LocalFile},State) -> 184 log(heading(recv,State#state.target_name), 185 "RemoteFile: ~tp\nLocalFile: ~tp\n",[RemoteFile,LocalFile]), 186 Result = ftp:recv(State#state.ftp_pid,RemoteFile,LocalFile), 187 {Result,State}; 188handle_msg({cd,Dir},State) -> 189 log(heading(cd,State#state.target_name),"Dir: ~tp\n",[Dir]), 190 Result = ftp:cd(State#state.ftp_pid,Dir), 191 {Result,State}; 192handle_msg({ls,Dir},State) -> 193 log(heading(ls,State#state.target_name),"Dir: ~tp\n",[Dir]), 194 Result = ftp:ls(State#state.ftp_pid,Dir), 195 {Result,State}; 196handle_msg({type,Type},State) -> 197 log(heading(type,State#state.target_name),"Type: ~tp\n",[Type]), 198 Result = ftp:type(State#state.ftp_pid,Type), 199 {Result,State}; 200handle_msg({delete,File},State) -> 201 log(heading(delete,State#state.target_name),"Delete file: ~tp\n",[File]), 202 Result = ftp:delete(State#state.ftp_pid,File), 203 {Result,State}. 204 205reconnect(_Addr,_State) -> 206 {error,no_reconnection_of_ftp}. 207 208terminate(FtpPid,State) -> 209 log(heading(terminate,State#state.target_name), 210 "Closing FTP connection.\nHandle: ~p\n",[FtpPid]), 211 ftp:stop_service(FtpPid). 212 213 214%%%================================================================= 215%%% Internal function 216get_handle(Pid) when is_pid(Pid) -> 217 {ok,Pid}; 218get_handle(Name) -> 219 case ct_util:get_connection(Name,?MODULE) of 220 {ok,{Pid,_}} -> 221 {ok,Pid}; 222 {error,no_registered_connection} -> 223 open(Name); 224 Error -> 225 Error 226 end. 227 228full_addr({Ip,Port}) -> 229 {Ip,Port}; 230full_addr(Ip) -> 231 {Ip,?DEFAULT_PORT}. 232 233call(Pid,Msg) -> 234 ct_gen_conn:call(Pid,Msg). 235 236 237heading(Function,Name) -> 238 io_lib:format("ct_ftp:~tw ~tp",[Function,Name]). 239 240log(Heading,Str,Args) -> 241 ct_gen_conn:log(Heading,Str,Args). 242 243 244open_and_do(Name,Fun) -> 245 case open(Name) of 246 {ok,Ftp} -> 247 R = Fun(Ftp), 248 close(Ftp), 249 R; 250 Error -> 251 Error 252 end. 253 254 255