From 309f9bdf05708c8d996e6bfd1534c8829affb810 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Fri, 5 Jun 2026 12:51:10 +0400 Subject: [PATCH 01/13] A function has been added that identifies active IP addresses by retrieving the network address --- src/Scansftp.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/Scansftp.py diff --git a/src/Scansftp.py b/src/Scansftp.py new file mode 100644 index 0000000..7c86a96 --- /dev/null +++ b/src/Scansftp.py @@ -0,0 +1,42 @@ +from scapy.all import ARP, Ether, srp +import netifaces +import ipaddress + +# a function that retrieves the network address of the connected interface +def get_local_network(): + # Find the interface used by the default gateway + gateway_info = netifaces.gateways() + interface = gateway_info['default'][netifaces.AF_INET][1] + + # Interface IP and netmask information + addr_info = netifaces.ifaddresses(interface)[netifaces.AF_INET][0] + + ip_addr = addr_info['addr'] + netmask = addr_info['netmask'] + + # Create a network address + network = ipaddress.IPv4Network(f"{ip_addr}/{netmask}", strict=False) + + return str(network) + + + +def arp_scan(network): + ether = Ether(dst="ff:ff:ff:ff:ff:ff") # Broadcast Ethernet frame + arp = ARP(pdst=network) # ARP package + + packet = ether / arp + + result = srp(packet, timeout=2, verbose=0)[0] # send package + + devices = [] + + for sent, received in result: + devices.append({"ip": received.psrc}) + + return devices + +#network = get_local_network() +#print(network) +#print(arp_scan(network)) + From c22f4be76b1f02149f3f35468846365c0a3e4000 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Fri, 5 Jun 2026 16:31:56 +0400 Subject: [PATCH 02/13] A function has been added that identifies IP addresses providing SFTP service by checking the SSH port of active IP addresses --- src/Scansftp.py | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/Scansftp.py b/src/Scansftp.py index 7c86a96..b10e97e 100644 --- a/src/Scansftp.py +++ b/src/Scansftp.py @@ -1,6 +1,8 @@ from scapy.all import ARP, Ether, srp import netifaces import ipaddress +import paramiko +import socket # a function that retrieves the network address of the connected interface def get_local_network(): @@ -20,8 +22,7 @@ def get_local_network(): return str(network) - -def arp_scan(network): +def scan_devices(network): ether = Ether(dst="ff:ff:ff:ff:ff:ff") # Broadcast Ethernet frame arp = ARP(pdst=network) # ARP package @@ -36,7 +37,40 @@ def arp_scan(network): return devices -#network = get_local_network() -#print(network) -#print(arp_scan(network)) + +def is_sftp_server(host, port=22, timeout=3): + # Checking if the SSH port is open + try: + sock = socket.create_connection((host, port), timeout=timeout) + sock.close() + except (socket.timeout, ConnectionRefusedError, OSError): + return False + + # Sending a fake credential results in an AuthenticationException → This means SFTP exists + transport = paramiko.Transport((host, port)) + transport.banner_timeout = timeout + + try: + transport.connect( + username='__probe__', + password='__probe__' + ) + return True + + except paramiko.AuthenticationException: + return True # an authentication error means the SFTP service is active + + except paramiko.SSHException: + return False # SSH handshake failed + + except Exception: + return False + +#netaddress = get_local_network() +#devices = scan_devices(netaddress) +#for d in devices: +# if is_sftp_server(d['ip']): +# print(f"{d} -- SFTP VAR") +# else: +# print(f"{d} -- SFTP YOK") From 9d2807e4f0d59040ab447ce4a11df6d8a6075d46 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sat, 6 Jun 2026 15:20:47 +0400 Subject: [PATCH 03/13] A dedicated section has been added to display SFTP servers after they have been scanned, and clicking the scan button will show a list of the addresses found --- src/MainWindow.py | 45 ++++++++++++++++++++++++++-- ui/MainWindow.glade | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/MainWindow.py b/src/MainWindow.py index efb9a3b..ad1d6aa 100644 --- a/src/MainWindow.py +++ b/src/MainWindow.py @@ -14,6 +14,8 @@ from UserSettings import UserSettings +import Scansftp # sftp scan function library + import locale from locale import gettext as _ @@ -213,6 +215,8 @@ def UI(str): self.box_user_domain_pass = UI("box_user_domain_pass") self.box_anonym = UI("box_anonym") self.btn_mount_connect = UI("btn_mount_connect") + self.btn_sftp_scan = UI("btn_sftp_scan") # sftp scan button + self.sftp_listbox = UI("sftp_listbox") # sftp list box self.mount_password_options = UI("mount_password_options") self.mount_anonym_options = UI("mount_anonym_options") self.popover_connect = UI("popover_connect") @@ -2096,6 +2100,38 @@ def add_to_recent_listbox(self, uri, name): box.name = "{} {}".format(uri, name).strip() self.listbox_recent_servers.add(box) + + # sftp scan function + def on_sftp_scan(self, button): + netaddress = Scansftp.get_local_network() + scanned_devices = Scansftp.scan_devices(netaddress) + for d in scanned_devices: + if Scansftp.is_sftp_server(d['ip']): + linebutton = self.make_sftp_listbox_button(d['ip'], on_clicked=self.server_entry_settext) + self.sftp_listbox.add(linebutton) + self.sftp_listbox.show_all() + + def make_sftp_listbox_button(self, label_text, on_clicked=None): + # Row oluştur + row = Gtk.ListBoxRow() + + # Button oluştur. Align/halign ile düzenleme yapabilirsiniz. + btn = Gtk.Button(label=label_text) + btn.set_hexpand(True) + btn.set_halign(Gtk.Align.FILL) + + # Eğer callback verildiyse bağla; handler'a (button, user_data) gönderecek şekilde sar + if on_clicked is not None: + btn.connect("clicked", on_clicked) + # Button'u row içine ekle + row.add(btn) + return row + + def server_entry_settext(self, button): + ip = button.get_label() + self.entry_addr.set_text("sftp://"+ip) + + def remove_from_recent_clicked(self, button): for row in self.listbox_recent_servers: if row.get_children()[0].name == button.name: @@ -2103,7 +2139,7 @@ def remove_from_recent_clicked(self, button): self.UserSettings.removeRecentServer(button.name) - def on_btn_mount_connect_clicked(self, button, from_saved=False, saved_uri="", from_places=False): + def on_btn_mount_connect_clicked(self, button, from_saved=False, saved_uri="", from_places=False, scan_req=False): def get_uri_name(source_object): try: uri = source_object.get_uri() @@ -2234,7 +2270,12 @@ def ask_question_cb(mount_operation, message, choices): if not from_saved: self.popover_connect.popdown() - addr = self.entry_addr.get_text() + if scan_req == False: + print("scan_req False") + addr = self.entry_addr.get_text() + else: + print("scan_req True") + addr = scan_req file = Gio.File.new_for_commandline_arg(addr) mount_operation = Gio.MountOperation() diff --git a/ui/MainWindow.glade b/ui/MainWindow.glade index 249ce41..f630210 100644 --- a/ui/MainWindow.glade +++ b/ui/MainWindow.glade @@ -2223,6 +2223,79 @@ Fatih Altun <fatih.altun@pardus.org.tr> 1 + + + True + False + + + False + True + 2 + + + + + True + False + vertical + + + True + False + Find the servers connected to the network: + + + False + True + 0 + + + + + True + True + in + + + True + False + + + True + False + + + + + + + False + True + 1 + + + + + Scan + True + True + True + + + + False + True + 2 + + + + + False + True + 3 + + From 4d252af250c808ac657cb7dcf4f0bcf4eaeb86b8 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sat, 6 Jun 2026 20:46:36 +0400 Subject: [PATCH 04/13] The ability to identify active IP addresses by sending ARP packets with Scapy has been removed. Due to Scapy's inherently heavy architecture, a manual approach has been preferred for this task --- src/Scansftp.py | 71 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/src/Scansftp.py b/src/Scansftp.py index b10e97e..251e5ec 100644 --- a/src/Scansftp.py +++ b/src/Scansftp.py @@ -1,8 +1,10 @@ -from scapy.all import ARP, Ether, srp -import netifaces +import subprocess +import socket import ipaddress +from concurrent.futures import ThreadPoolExecutor, as_completed +import time import paramiko -import socket +import netifaces # a function that retrieves the network address of the connected interface def get_local_network(): @@ -22,23 +24,23 @@ def get_local_network(): return str(network) -def scan_devices(network): - ether = Ether(dst="ff:ff:ff:ff:ff:ff") # Broadcast Ethernet frame - arp = ARP(pdst=network) # ARP package - - packet = ether / arp - - result = srp(packet, timeout=2, verbose=0)[0] # send package - - devices = [] - - for sent, received in result: - devices.append({"ip": received.psrc}) +def get_ip_neigh(): + ips = set() + try: + out = subprocess.check_output(["ip", "neigh"]).decode() + for line in out.splitlines(): + parts = line.split() + if len(parts) > 0: + ip = parts[0] + if ip.count(".") == 3: # IPv4 basic filter + ips.add(ip) + except Exception as e: + print("ip neigh error:", e) - return devices + return ips -def is_sftp_server(host, port=22, timeout=3): +def check_ssh_sftp(host, port=22, timeout=3): # Checking if the SSH port is open try: sock = socket.create_connection((host, port), timeout=timeout) @@ -66,11 +68,34 @@ def is_sftp_server(host, port=22, timeout=3): except Exception: return False +# scan devices +def scan(network, max_threads=30, delay=0.02): + net = ipaddress.ip_network(network, strict=False) + results = [] + + def worker(ip): + ip = str(ip) + if check_ssh_sftp(ip): # this address is being checked to see if it is an SSH server + return ip + return None + + with ThreadPoolExecutor(max_workers=max_threads) as executor: + futures = [] + + for ip in net.hosts(): + futures.append(executor.submit(worker, ip)) + time.sleep(delay) + + for f in as_completed(futures): + res = f.result() + if res: + results.append(res) + + return results + + #netaddress = get_local_network() -#devices = scan_devices(netaddress) -#for d in devices: -# if is_sftp_server(d['ip']): -# print(f"{d} -- SFTP VAR") -# else: -# print(f"{d} -- SFTP YOK") +#hosts = scan(netaddress) +#for h in hosts: +# print(h) From c72c569ecb3eb238b99583e6e35755083a9df9a4 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sat, 6 Jun 2026 23:56:05 +0400 Subject: [PATCH 05/13] The interface was optimized for SFTP server scanning, discovery, and listing tasks --- src/MainWindow.py | 56 +++++++++++++++++++++------------ ui/MainWindow.glade | 75 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/MainWindow.py b/src/MainWindow.py index ad1d6aa..e19f75c 100644 --- a/src/MainWindow.py +++ b/src/MainWindow.py @@ -14,6 +14,7 @@ from UserSettings import UserSettings +import threading import Scansftp # sftp scan function library import locale @@ -217,6 +218,8 @@ def UI(str): self.btn_mount_connect = UI("btn_mount_connect") self.btn_sftp_scan = UI("btn_sftp_scan") # sftp scan button self.sftp_listbox = UI("sftp_listbox") # sftp list box + self.sftp_stack = UI("sftp_stack") # sftp stack panel + self.scrolledwindow = UI("scrolledwindow") self.mount_password_options = UI("mount_password_options") self.mount_anonym_options = UI("mount_anonym_options") self.popover_connect = UI("popover_connect") @@ -2100,15 +2103,40 @@ def add_to_recent_listbox(self, uri, name): box.name = "{} {}".format(uri, name).strip() self.listbox_recent_servers.add(box) + def remove_from_recent_clicked(self, button): + for row in self.listbox_recent_servers: + if row.get_children()[0].name == button.name: + self.listbox_recent_servers.remove(row) + + self.UserSettings.removeRecentServer(button.name) + + # sftp scan function def on_sftp_scan(self, button): - netaddress = Scansftp.get_local_network() - scanned_devices = Scansftp.scan_devices(netaddress) + self.sftp_stack.set_visible_child_name('page1') + # Arka plan thread başlat + threading.Thread(target=self.scan_process, daemon=True).start() + + def scan_process(self): + try: + netaddress = Scansftp.get_local_network() + scanned_devices = Scansftp.scan_devices(netaddress) + except Exception as e: + #GLib.idle_add(self._on_scan_done, None, e) + return + GLib.idle_add(self.sftp_listboxadd, scanned_devices) + + def sftp_listboxadd(self, scanned_devices): + # Listeyi güncelle + self.sftp_listbox.foreach(lambda w: self.sftp_listbox.remove(w)) + self.sftp_listbox.set_hexpand(True) + self.sftp_listbox.set_vexpand(True) for d in scanned_devices: - if Scansftp.is_sftp_server(d['ip']): - linebutton = self.make_sftp_listbox_button(d['ip'], on_clicked=self.server_entry_settext) - self.sftp_listbox.add(linebutton) + row = self.make_sftp_listbox_button(d, on_clicked=self.server_entry_settext) + self.sftp_listbox.add(row) + + self.sftp_stack.set_visible_child_name('page0') self.sftp_listbox.show_all() def make_sftp_listbox_button(self, label_text, on_clicked=None): @@ -2128,18 +2156,11 @@ def make_sftp_listbox_button(self, label_text, on_clicked=None): return row def server_entry_settext(self, button): - ip = button.get_label() + ip = button.get_label().strip() self.entry_addr.set_text("sftp://"+ip) - def remove_from_recent_clicked(self, button): - for row in self.listbox_recent_servers: - if row.get_children()[0].name == button.name: - self.listbox_recent_servers.remove(row) - - self.UserSettings.removeRecentServer(button.name) - - def on_btn_mount_connect_clicked(self, button, from_saved=False, saved_uri="", from_places=False, scan_req=False): + def on_btn_mount_connect_clicked(self, button, from_saved=False, saved_uri="", from_places=False): def get_uri_name(source_object): try: uri = source_object.get_uri() @@ -2270,12 +2291,7 @@ def ask_question_cb(mount_operation, message, choices): if not from_saved: self.popover_connect.popdown() - if scan_req == False: - print("scan_req False") - addr = self.entry_addr.get_text() - else: - print("scan_req True") - addr = scan_req + addr = self.entry_addr.get_text() file = Gio.File.new_for_commandline_arg(addr) mount_operation = Gio.MountOperation() diff --git a/ui/MainWindow.glade b/ui/MainWindow.glade index f630210..abf549b 100644 --- a/ui/MainWindow.glade +++ b/ui/MainWindow.glade @@ -2238,11 +2238,13 @@ Fatih Altun <fatih.altun@pardus.org.tr> True False + 10 vertical True False + 13 Find the servers connected to the network: @@ -2252,21 +2254,83 @@ Fatih Altun <fatih.altun@pardus.org.tr> - + True - True - in + False - + + True + False + vertical + + + True + True + 3 + in + True + True + + + True + False + + + True + False + + + + + + + False + True + 0 + + + + + page0 + page0 + + + + True False + vertical + True - + True False + True + + False + True + 0 + + + + + True + False + Scanning the SFTP servers on the network... + + + False + True + 1 + + + page1 + page1 + 1 + @@ -2281,6 +2345,7 @@ Fatih Altun <fatih.altun@pardus.org.tr> True True True + 16 From 33ce367a4f432521c2b199e2a7e7a646093b82cd Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sun, 7 Jun 2026 00:00:08 +0400 Subject: [PATCH 06/13] Translations have been edited --- src/MainWindow.py | 11 ++++------- src/Scansftp.py | 3 ++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/MainWindow.py b/src/MainWindow.py index e19f75c..d280e3b 100644 --- a/src/MainWindow.py +++ b/src/MainWindow.py @@ -2115,7 +2115,7 @@ def remove_from_recent_clicked(self, button): # sftp scan function def on_sftp_scan(self, button): self.sftp_stack.set_visible_child_name('page1') - # Arka plan thread başlat + # Start background thread threading.Thread(target=self.scan_process, daemon=True).start() def scan_process(self): @@ -2123,12 +2123,11 @@ def scan_process(self): netaddress = Scansftp.get_local_network() scanned_devices = Scansftp.scan_devices(netaddress) except Exception as e: - #GLib.idle_add(self._on_scan_done, None, e) return GLib.idle_add(self.sftp_listboxadd, scanned_devices) def sftp_listboxadd(self, scanned_devices): - # Listeyi güncelle + # Update the list self.sftp_listbox.foreach(lambda w: self.sftp_listbox.remove(w)) self.sftp_listbox.set_hexpand(True) self.sftp_listbox.set_vexpand(True) @@ -2140,18 +2139,16 @@ def sftp_listboxadd(self, scanned_devices): self.sftp_listbox.show_all() def make_sftp_listbox_button(self, label_text, on_clicked=None): - # Row oluştur + # Create row row = Gtk.ListBoxRow() - # Button oluştur. Align/halign ile düzenleme yapabilirsiniz. + # Create a button. You can edit it using align/halign btn = Gtk.Button(label=label_text) btn.set_hexpand(True) btn.set_halign(Gtk.Align.FILL) - # Eğer callback verildiyse bağla; handler'a (button, user_data) gönderecek şekilde sar if on_clicked is not None: btn.connect("clicked", on_clicked) - # Button'u row içine ekle row.add(btn) return row diff --git a/src/Scansftp.py b/src/Scansftp.py index 251e5ec..187dd17 100644 --- a/src/Scansftp.py +++ b/src/Scansftp.py @@ -69,7 +69,7 @@ def check_ssh_sftp(host, port=22, timeout=3): return False # scan devices -def scan(network, max_threads=30, delay=0.02): +def scan_devices(network, max_threads=30, delay=0.02): net = ipaddress.ip_network(network, strict=False) results = [] @@ -91,6 +91,7 @@ def worker(ip): if res: results.append(res) + print(results) return results From eb834929327cece51740365b5b9aecaad70206db Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sun, 7 Jun 2026 00:01:07 +0400 Subject: [PATCH 07/13] Updated depends --- debian/control | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 4e56185..f56e60f 100644 --- a/debian/control +++ b/debian/control @@ -15,7 +15,8 @@ Depends: ${misc:Depends}, gir1.2-glib-2.0, gir1.2-gtk-3.0, gir1.2-notify-0.7, - gir1.2-pango-1.0 + gir1.2-pango-1.0, + python3-paramiko Recommends: gvfs-fuse, libglib2.0-bin Description: My Computer, shows general information about your computer. From 2b1a27b3364cd2e4bb2331f35110974e4da83a12 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sun, 7 Jun 2026 00:05:28 +0400 Subject: [PATCH 08/13] The scan button was disabled during the scanning process --- src/MainWindow.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/MainWindow.py b/src/MainWindow.py index d280e3b..3afb520 100644 --- a/src/MainWindow.py +++ b/src/MainWindow.py @@ -2115,6 +2115,7 @@ def remove_from_recent_clicked(self, button): # sftp scan function def on_sftp_scan(self, button): self.sftp_stack.set_visible_child_name('page1') + self.btn_sftp_scan.set_sensitive(False) # Start background thread threading.Thread(target=self.scan_process, daemon=True).start() @@ -2137,6 +2138,7 @@ def sftp_listboxadd(self, scanned_devices): self.sftp_stack.set_visible_child_name('page0') self.sftp_listbox.show_all() + self.btn_sftp_scan.set_sensitive(True) def make_sftp_listbox_button(self, label_text, on_clicked=None): # Create row From 682ecf4c8f148ba2540d7b3fc0f4b4c60a3a4727 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sun, 7 Jun 2026 06:32:44 +0400 Subject: [PATCH 09/13] Updated translate file --- po/tr.po | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/po/tr.po b/po/tr.po index 2a259ab..c2faa4f 100644 --- a/po/tr.po +++ b/po/tr.po @@ -512,3 +512,19 @@ msgstr "# not: görünmesini sağlamak için kare işareti kaldırın" #~ msgid "Website" #~ msgstr "Website" + +#: ui/MainWindow.glade:2248 +msgid "Find the servers connected to the network:" +msgstr "Ağa bağlı sunucuları bulun:" + +#: ui/MainWindow.glade:2248 +msgid "Scanning the SFTP servers on the network.." +msgstr "Ağdaki SFTP sunucuları taranıyor..." + +#: ui/MainWindow.glade:2320 +msgid "Scan" +msgstr "Tara" + +#: ui/MainWindow.glade:2344 +msgid "Scan" +msgstr "Tara" From 74cee16eaf8b51b6e37b7dc9b0d8c6fe5216eaf7 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sun, 7 Jun 2026 06:34:02 +0400 Subject: [PATCH 10/13] Updated setup file --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index ea70c31..77c8ec7 100644 --- a/setup.py +++ b/setup.py @@ -45,6 +45,7 @@ def create_mo_files(): "src/DiskManager.py", "src/Unmount.py", "src/UserSettings.py", + "src/Scansftp.py", "src/__version__" ]), ("/usr/share/pardus/pardus-mycomputer/ui", From 6c3cee15b635512beef823c905ef2e6f956bc8a0 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sun, 7 Jun 2026 06:42:32 +0400 Subject: [PATCH 11/13] Updated --- po/files | 1 + 1 file changed, 1 insertion(+) diff --git a/po/files b/po/files index 414622e..0f6c8e9 100644 --- a/po/files +++ b/po/files @@ -1,3 +1,4 @@ ui/MainWindow.glade src/MainWindow.py src/UserSettings.py +src/Scansftp.py \ No newline at end of file From 7ac94ebd084fdc50c658a8356a0661c59e82cb24 Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sun, 7 Jun 2026 06:47:58 +0400 Subject: [PATCH 12/13] Updated translate file --- po/tr.po | 4 ---- 1 file changed, 4 deletions(-) diff --git a/po/tr.po b/po/tr.po index c2faa4f..38d2b29 100644 --- a/po/tr.po +++ b/po/tr.po @@ -521,10 +521,6 @@ msgstr "Ağa bağlı sunucuları bulun:" msgid "Scanning the SFTP servers on the network.." msgstr "Ağdaki SFTP sunucuları taranıyor..." -#: ui/MainWindow.glade:2320 -msgid "Scan" -msgstr "Tara" - #: ui/MainWindow.glade:2344 msgid "Scan" msgstr "Tara" From 597da9af2845f113385273d224f4f54824c4a4cb Mon Sep 17 00:00:00 2001 From: Heydar Ismayilli Date: Sun, 7 Jun 2026 06:59:30 +0400 Subject: [PATCH 13/13] Updated translate file --- po/tr.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/tr.po b/po/tr.po index 38d2b29..c64051c 100644 --- a/po/tr.po +++ b/po/tr.po @@ -518,7 +518,7 @@ msgid "Find the servers connected to the network:" msgstr "Ağa bağlı sunucuları bulun:" #: ui/MainWindow.glade:2248 -msgid "Scanning the SFTP servers on the network.." +msgid "Scanning the SFTP servers on the network..." msgstr "Ağdaki SFTP sunucuları taranıyor..." #: ui/MainWindow.glade:2344